Files
minhthu/lib/features/auth/presentation/providers/auth_provider.dart
2025-10-28 23:46:07 +07:00

178 lines
4.6 KiB
Dart

import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../data/models/login_request_model.dart';
import '../../domain/entities/user_entity.dart';
import '../../domain/usecases/login_usecase.dart';
/// Authentication state
///
/// Represents the current authentication status and user data
class AuthState extends Equatable {
/// Current authenticated user (null if not authenticated)
final UserEntity? user;
/// Whether user is authenticated
final bool isAuthenticated;
/// Whether an authentication operation is in progress
final bool isLoading;
/// Error message if authentication fails
final String? error;
const AuthState({
this.user,
this.isAuthenticated = false,
this.isLoading = false,
this.error,
});
/// Initial state (not authenticated, not loading)
const AuthState.initial()
: user = null,
isAuthenticated = false,
isLoading = false,
error = null;
/// Loading state
const AuthState.loading()
: user = null,
isAuthenticated = false,
isLoading = true,
error = null;
/// Authenticated state with user data
const AuthState.authenticated(UserEntity user)
: user = user,
isAuthenticated = true,
isLoading = false,
error = null;
/// Error state
const AuthState.error(String message)
: user = null,
isAuthenticated = false,
isLoading = false,
error = message;
/// Create a copy with modified fields
AuthState copyWith({
UserEntity? user,
bool? isAuthenticated,
bool? isLoading,
String? error,
}) {
return AuthState(
user: user ?? this.user,
isAuthenticated: isAuthenticated ?? this.isAuthenticated,
isLoading: isLoading ?? this.isLoading,
error: error,
);
}
@override
List<Object?> get props => [user, isAuthenticated, isLoading, error];
@override
String toString() {
return 'AuthState(isAuthenticated: $isAuthenticated, isLoading: $isLoading, error: $error, user: $user)';
}
}
/// Auth state notifier that manages authentication state
///
/// Handles login, logout, and authentication status checks
class AuthNotifier extends StateNotifier<AuthState> {
final LoginUseCase loginUseCase;
final LogoutUseCase logoutUseCase;
final CheckAuthStatusUseCase checkAuthStatusUseCase;
final GetCurrentUserUseCase getCurrentUserUseCase;
AuthNotifier({
required this.loginUseCase,
required this.logoutUseCase,
required this.checkAuthStatusUseCase,
required this.getCurrentUserUseCase,
}) : super(const AuthState.initial());
/// Login with username and password
///
/// Updates state to loading, then either authenticated or error
Future<void> login(String username, String password) async {
// Set loading state
state = const AuthState.loading();
// Create login request
final request = LoginRequestModel(
username: username,
password: password,
);
// Call login use case
final result = await loginUseCase(request);
// Handle result
result.fold(
(failure) {
// Login failed - set error state
state = AuthState.error(failure.message);
},
(user) {
// Login successful - set authenticated state
state = AuthState.authenticated(user);
},
);
}
/// Logout current user
///
/// Clears authentication data and returns to initial state
Future<void> logout() async {
// Clear tokens from secure storage
await logoutUseCase();
// Always reset to initial state (clear local data even if API call fails)
state = const AuthState.initial();
}
/// Check authentication status on app start
///
/// Loads user data from storage if authenticated
Future<void> checkAuthStatus() async {
// Check if user is authenticated
final isAuthenticated = await checkAuthStatusUseCase();
if (isAuthenticated) {
// Try to load user data
final result = await getCurrentUserUseCase();
result.fold(
(failure) {
// Failed to load user data - reset to initial state
state = const AuthState.initial();
},
(user) {
// User data loaded - set authenticated state
state = AuthState.authenticated(user);
},
);
} else {
// Not authenticated - initial state
state = const AuthState.initial();
}
}
/// Clear error message
void clearError() {
if (state.error != null) {
state = state.copyWith(error: null);
}
}
/// Reset to initial state
void reset() {
state = const AuthState.initial();
}
}