fill
This commit is contained in:
190
lib/features/auth/presentation/providers/auth_provider.dart
Normal file
190
lib/features/auth/presentation/providers/auth_provider.dart
Normal file
@@ -0,0 +1,190 @@
|
||||
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 {
|
||||
// Set loading state
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
// Call logout use case
|
||||
final result = await logoutUseCase();
|
||||
|
||||
// Handle result
|
||||
result.fold(
|
||||
(failure) {
|
||||
// Logout failed - but still reset to initial state
|
||||
// (local data should be cleared even if API call fails)
|
||||
state = const AuthState.initial();
|
||||
},
|
||||
(_) {
|
||||
// Logout successful - reset to initial state
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user