128 lines
4.2 KiB
Dart
128 lines
4.2 KiB
Dart
import 'dart:async';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../../domain/repositories/auth_repository.dart';
|
|
import '../../domain/entities/user_model.dart';
|
|
import 'document_provider.dart';
|
|
import 'archives_provider.dart';
|
|
import 'student_provider.dart' hide academicYearsProvider;
|
|
import 'navigation_provider.dart';
|
|
import 'reports_provider.dart';
|
|
import 'connected_users_provider.dart';
|
|
import '../../core/services/foreground_sync_service.dart';
|
|
|
|
final authRepositoryProvider = Provider<AuthRepository>(
|
|
(ref) => AuthRepository(),
|
|
);
|
|
|
|
final authProvider = AsyncNotifierProvider<AuthNotifier, UserModel?>(() {
|
|
return AuthNotifier();
|
|
});
|
|
|
|
class AuthNotifier extends AsyncNotifier<UserModel?> {
|
|
@override
|
|
FutureOr<UserModel?> build() {
|
|
return null; // Always starts null; auto-login handled in SplashScreen
|
|
}
|
|
|
|
Future<bool> login(
|
|
String username,
|
|
String password, {
|
|
bool rememberMe = false,
|
|
}) async {
|
|
state = const AsyncLoading();
|
|
try {
|
|
final repository = ref.read(authRepositoryProvider);
|
|
final user = await repository.login(
|
|
username,
|
|
password,
|
|
rememberMe: rememberMe,
|
|
);
|
|
state = AsyncData(user);
|
|
ref.read(heartbeatServiceProvider).start(user);
|
|
ForegroundSyncService.start();
|
|
return true;
|
|
} catch (e, st) {
|
|
state = AsyncError(e, st);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Called from SplashScreen — tries to auto-login from stored token.
|
|
Future<UserModel?> tryAutoLogin() async {
|
|
try {
|
|
final repository = ref.read(authRepositoryProvider);
|
|
final user = await repository.tryAutoLogin();
|
|
if (user != null) {
|
|
state = AsyncData(user);
|
|
ref.read(heartbeatServiceProvider).start(user);
|
|
ForegroundSyncService.start();
|
|
}
|
|
return user;
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
Future<void> logout() async {
|
|
ref.read(heartbeatServiceProvider).stop();
|
|
ForegroundSyncService.stop();
|
|
final repository = ref.read(authRepositoryProvider);
|
|
await repository.logout();
|
|
state = const AsyncData(null);
|
|
|
|
// Invalidate all persistent providers so the next login starts clean.
|
|
// autoDispose providers clean themselves up automatically; only persistent ones need this.
|
|
_invalidateAllProviders();
|
|
}
|
|
|
|
void _invalidateAllProviders() {
|
|
// Only reset persistent filter and navigation states.
|
|
// autoDispose FutureProviders clean themselves up automatically when screens unmount;
|
|
// invalidating them during logout triggers unnecessary unauthenticated API requests.
|
|
ref.invalidate(documentQueryProvider);
|
|
ref.invalidate(openedFolderProvider);
|
|
ref.invalidate(archiveQueryProvider);
|
|
ref.invalidate(studentQueryProvider);
|
|
ref.invalidate(activeTabProvider);
|
|
|
|
ref.invalidate(selectedAcademicYearIdProvider);
|
|
ref.invalidate(selectedGradeLevelProvider);
|
|
ref.invalidate(selectedSectionIdProvider);
|
|
ref.invalidate(selectedStatusFilterProvider);
|
|
ref.invalidate(showOnlyMissingDocsProvider);
|
|
ref.invalidate(filterPanelExpandedProvider);
|
|
ref.invalidate(missingDocsFilterExpandedProvider);
|
|
ref.invalidate(yearlyComparisonSelectedYearsProvider);
|
|
ref.invalidate(yearlyComparisonSelectedStatusesProvider);
|
|
}
|
|
|
|
Future<void> refreshUser() async {
|
|
try {
|
|
final repository = ref.read(authRepositoryProvider);
|
|
final updatedUser = await repository.getProfile();
|
|
state = AsyncData(updatedUser);
|
|
} catch (e) {
|
|
// Don't emit error state to prevent UI disruptions on background refresh failures
|
|
print('Background refresh failed: $e');
|
|
}
|
|
}
|
|
|
|
Future<bool> verifyPassword(String password) async {
|
|
final repository = ref.read(authRepositoryProvider);
|
|
return await repository.verifyPassword(password);
|
|
}
|
|
}
|
|
|
|
// Full profile data provider
|
|
final profileProvider = FutureProvider.autoDispose<UserModel>((ref) async {
|
|
final repository = ref.read(authRepositoryProvider);
|
|
return await repository.getProfile();
|
|
});
|
|
|
|
// Super Admin: pending password reset requests
|
|
final resetRequestsProvider =
|
|
FutureProvider.autoDispose<List<Map<String, dynamic>>>((ref) async {
|
|
final repository = ref.read(authRepositoryProvider);
|
|
return await repository.getResetRequests();
|
|
});
|