Files
AutoJudge-Flutter/lib/services/app_initialization_service.dart
2025-11-13 09:14:49 +08:00

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'
')';
}
}