276 lines
7.6 KiB
Dart
276 lines
7.6 KiB
Dart
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<InitializationResult> initialize() async {
|
|
final startTime = DateTime.now();
|
|
final steps = <InitializationStep>[];
|
|
|
|
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<InitializationStep> _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<InitializationStep> _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<InitializationStep> _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<InitializationStep> _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<InitializationStep> 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<InitializationStep> get failedSteps =>
|
|
steps.where((step) => !step.success).toList();
|
|
|
|
/// Get successful steps
|
|
List<InitializationStep> 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'
|
|
')';
|
|
}
|
|
}
|