import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:flutter/foundation.dart'; import '../constants/environment_config.dart'; import '../database/hive_service.dart'; import '../database/models/app_settings.dart'; import '../database/providers/database_providers.dart'; import '../database/repositories/settings_repository.dart'; import '../database/repositories/cache_repository.dart'; import '../database/repositories/user_preferences_repository.dart'; part 'app_providers.g.dart'; /// App initialization state enum AppInitializationState { uninitialized, initializing, initialized, error, } /// App initialization data class AppInitializationData { final AppInitializationState state; final String? error; final DateTime? initializedAt; const AppInitializationData({ required this.state, this.error, this.initializedAt, }); AppInitializationData copyWith({ AppInitializationState? state, String? error, DateTime? initializedAt, }) { return AppInitializationData( state: state ?? this.state, error: error ?? this.error, initializedAt: initializedAt ?? this.initializedAt, ); } } /// Repository providers @riverpod CacheRepository cacheRepository(CacheRepositoryRef ref) { return CacheRepository(); } @riverpod UserPreferencesRepository userPreferencesRepository(UserPreferencesRepositoryRef ref) { return UserPreferencesRepository(); } /// App initialization provider @riverpod class AppInitialization extends _$AppInitialization { @override Future build() async { return _initializeApp(); } Future _initializeApp() async { try { debugPrint('๐Ÿš€ Starting app initialization...'); // Initialize Hive debugPrint('๐Ÿ“ฆ Initializing Hive database...'); // await HiveService.initialize(); // Initialize repositories debugPrint('๐Ÿ—‚๏ธ Initializing repositories...'); final settingsRepo = ref.read(settingsRepositoryProvider); final cacheRepo = ref.read(cacheRepositoryProvider); final userPrefsRepo = ref.read(userPreferencesRepositoryProvider); // Load initial settings debugPrint('โš™๏ธ Loading app settings...'); final settings = settingsRepo.getSettings(); // Initialize user preferences if needed debugPrint('๐Ÿ‘ค Initializing user preferences...'); userPrefsRepo.getPreferences(); // Perform any necessary migrations debugPrint('๐Ÿ”„ Checking for migrations...'); await _performMigrations(settingsRepo, settings); // Clean up expired cache entries debugPrint('๐Ÿงน Cleaning up expired cache...'); await cacheRepo.cleanExpiredItems(); debugPrint('โœ… App initialization completed successfully'); return AppInitializationData( state: AppInitializationState.initialized, initializedAt: DateTime.now(), ); } catch (error, stackTrace) { debugPrint('โŒ App initialization failed: $error'); debugPrint('Stack trace: $stackTrace'); return AppInitializationData( state: AppInitializationState.error, error: error.toString(), ); } } Future _performMigrations(SettingsRepository repo, AppSettings settings) async { // Add any migration logic here if (settings.version < 1) { debugPrint('๐Ÿ”„ Migrating settings to version 1...'); // Migration logic would go here } } /// Retry initialization Future retry() async { state = const AsyncValue.loading(); state = AsyncValue.data(await _initializeApp()); } /// Force re-initialization Future reinitialize() async { state = const AsyncValue.loading(); try { // Close all Hive boxes await HiveService.closeAll(); // Re-initialize everything state = AsyncValue.data(await _initializeApp()); } catch (error, stackTrace) { state = AsyncValue.error(error, stackTrace); } } } /// App version provider @riverpod String appVersion(AppVersionRef ref) { // This would typically come from package_info_plus return '1.0.0+1'; } /// App build mode provider @riverpod String appBuildMode(AppBuildModeRef ref) { if (kDebugMode) return 'debug'; if (kProfileMode) return 'profile'; return 'release'; } /// App ready state provider @riverpod bool isAppReady(IsAppReadyRef ref) { final initData = ref.watch(appInitializationProvider); return initData.when( data: (data) => data.state == AppInitializationState.initialized, loading: () => false, error: (_, __) => false, ); } /// Global app state notifier @riverpod class GlobalAppState extends _$GlobalAppState { @override Map build() { final initAsync = ref.watch(appInitializationProvider); final appVersion = ref.watch(appVersionProvider); final buildMode = ref.watch(appBuildModeProvider); return initAsync.when( data: (initData) => { 'isInitialized': initData.state == AppInitializationState.initialized, 'initializationState': initData.state, 'initializationError': initData.error, 'initializedAt': initData.initializedAt?.toIso8601String(), 'appVersion': appVersion, 'buildMode': buildMode, 'isReady': initData.state == AppInitializationState.initialized, }, loading: () => { 'isInitialized': false, 'initializationState': AppInitializationState.initializing, 'initializationError': null, 'initializedAt': null, 'appVersion': appVersion, 'buildMode': buildMode, 'isReady': false, }, error: (error, _) => { 'isInitialized': false, 'initializationState': AppInitializationState.error, 'initializationError': error.toString(), 'initializedAt': null, 'appVersion': appVersion, 'buildMode': buildMode, 'isReady': false, }, ); } /// Update global state void updateState(String key, dynamic value) { final currentState = Map.from(state); currentState[key] = value; state = currentState; } /// Reset global state void reset() { ref.invalidate(appInitializationProvider); } } /// Feature flags provider @riverpod class FeatureFlags extends _$FeatureFlags { @override Map build() { final buildMode = ref.watch(appBuildModeProvider); return { 'enableDebugMode': buildMode == 'debug', 'enableAnalytics': buildMode == 'release', 'enableCrashReporting': buildMode != 'debug', 'enablePerformanceMonitoring': true, 'enableOfflineMode': true, 'enableDarkMode': true, 'enableNotifications': true, }; } /// Check if feature is enabled bool isEnabled(String feature) { return state[feature] ?? false; } /// Enable feature void enableFeature(String feature) { state = {...state, feature: true}; } /// Disable feature void disableFeature(String feature) { state = {...state, feature: false}; } /// Toggle feature void toggleFeature(String feature) { final currentValue = state[feature] ?? false; state = {...state, feature: !currentValue}; } } /// App configuration provider @riverpod class AppConfiguration extends _$AppConfiguration { @override Map build() { final buildMode = ref.watch(appBuildModeProvider); return { // Environment-specific API configuration 'environment': EnvironmentConfig.currentEnvironment.name, 'baseUrl': EnvironmentConfig.baseUrl, 'apiPath': EnvironmentConfig.apiPath, 'fullBaseUrl': EnvironmentConfig.fullBaseUrl, 'connectTimeout': EnvironmentConfig.connectTimeout, 'receiveTimeout': EnvironmentConfig.receiveTimeout, 'sendTimeout': EnvironmentConfig.sendTimeout, 'maxRetries': EnvironmentConfig.maxRetries, 'retryDelay': EnvironmentConfig.retryDelay.inMilliseconds, // Environment-specific logging 'enableLogging': EnvironmentConfig.enableLogging, 'enableDetailedLogging': EnvironmentConfig.enableDetailedLogging, 'enableCertificatePinning': EnvironmentConfig.enableCertificatePinning, 'logLevel': EnvironmentConfig.enableDetailedLogging ? 'verbose' : 'error', // General configuration 'cacheTimeout': 3600000, // 1 hour in milliseconds 'maxCacheSize': 100 * 1024 * 1024, // 100MB 'imageQuality': 85, 'compressionEnabled': true, // Environment flags 'isDevelopment': EnvironmentConfig.isDevelopment, 'isStaging': EnvironmentConfig.isStaging, 'isProduction': EnvironmentConfig.isProduction, }; } /// Get configuration value T? getValue(String key) { return state[key] as T?; } /// Update configuration void updateConfiguration(String key, dynamic value) { state = {...state, key: value}; } /// Update multiple configurations void updateConfigurations(Map updates) { state = {...state, ...updates}; } } /// App lifecycle state provider @riverpod class AppLifecycleNotifier extends _$AppLifecycleNotifier { @override String build() { return 'resumed'; // Default state } void updateState(String newState) { state = newState; debugPrint('๐Ÿ“ฑ App lifecycle state changed to: $newState'); } } /// Error tracking provider @riverpod class ErrorTracker extends _$ErrorTracker { @override List> build() { return []; } /// Log error void logError(dynamic error, StackTrace? stackTrace, {Map? context}) { final errorEntry = { 'error': error.toString(), 'stackTrace': stackTrace?.toString(), 'timestamp': DateTime.now().toIso8601String(), 'context': context, }; state = [...state, errorEntry]; // Keep only last 100 errors to prevent memory issues if (state.length > 100) { state = state.sublist(state.length - 100); } debugPrint('๐Ÿ› Error logged: $error'); } /// Clear errors void clearErrors() { state = []; } /// Get recent errors List> getRecentErrors({int count = 10}) { return state.reversed.take(count).toList(); } } /// Environment debug information provider @riverpod Map environmentDebugInfo(EnvironmentDebugInfoRef ref) { return EnvironmentConfig.debugInfo; } /// API connectivity test provider @riverpod class ApiConnectivityTest extends _$ApiConnectivityTest { @override Future> build() async { return _testConnectivity(); } Future> _testConnectivity() async { try { debugPrint('๐Ÿ” Testing API connectivity to ${EnvironmentConfig.baseUrl}...'); final result = { 'baseUrl': EnvironmentConfig.baseUrl, 'fullBaseUrl': EnvironmentConfig.fullBaseUrl, 'loginUrl': EnvironmentConfig.loginUrl, 'environment': EnvironmentConfig.currentEnvironment.name, 'timestamp': DateTime.now().toIso8601String(), 'status': 'success', 'message': 'Configuration loaded successfully', 'endpoints': { 'login': EnvironmentConfig.loginUrl, 'register': EnvironmentConfig.registerUrl, 'refresh': EnvironmentConfig.refreshUrl, 'logout': EnvironmentConfig.logoutUrl, }, 'settings': { 'connectTimeout': EnvironmentConfig.connectTimeout, 'receiveTimeout': EnvironmentConfig.receiveTimeout, 'sendTimeout': EnvironmentConfig.sendTimeout, 'maxRetries': EnvironmentConfig.maxRetries, 'retryDelay': EnvironmentConfig.retryDelay.inMilliseconds, 'enableLogging': EnvironmentConfig.enableLogging, 'enableDetailedLogging': EnvironmentConfig.enableDetailedLogging, } }; debugPrint('โœ… API connectivity test completed successfully'); return result; } catch (error, stackTrace) { debugPrint('โŒ API connectivity test failed: $error'); debugPrint('Stack trace: $stackTrace'); return { 'status': 'error', 'error': error.toString(), 'timestamp': DateTime.now().toIso8601String(), 'baseUrl': EnvironmentConfig.baseUrl, }; } } /// Retry connectivity test Future retry() async { state = const AsyncValue.loading(); state = AsyncValue.data(await _testConnectivity()); } }