178 lines
4.6 KiB
Dart
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();
|
|
}
|
|
}
|