Files
ai_english/client/lib/features/auth/providers/auth_provider.dart
2025-11-17 14:09:17 +08:00

312 lines
7.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/models/user_model.dart';
import '../../../core/services/auth_service.dart';
import '../../../core/services/storage_service.dart';
import '../../../core/network/api_client.dart';
import '../../../core/errors/app_exception.dart';
/// 认证状态
class AuthState {
final User? user;
final bool isAuthenticated;
final bool isLoading;
final String? error;
const AuthState({
this.user,
this.isAuthenticated = false,
this.isLoading = false,
this.error,
});
AuthState copyWith({
User? user,
bool? isAuthenticated,
bool? isLoading,
String? error,
}) {
return AuthState(
user: user ?? this.user,
isAuthenticated: isAuthenticated ?? this.isAuthenticated,
isLoading: isLoading ?? this.isLoading,
error: error,
);
}
}
/// 认证状态管理器
class AuthNotifier extends StateNotifier<AuthState> {
final AuthService _authService;
final StorageService _storageService;
AuthNotifier(this._authService, this._storageService) : super(const AuthState()) {
_checkAuthStatus();
}
/// 检查认证状态
Future<void> _checkAuthStatus() async {
try {
final token = await _storageService.getToken();
if (token != null && token.isNotEmpty) {
// 获取真实用户信息
try {
final user = await _authService.getUserInfo();
state = state.copyWith(
user: user,
isAuthenticated: true,
);
} catch (e) {
// Token可能已过期清除token
await _storageService.clearTokens();
}
}
} catch (e) {
// 忽略错误,保持未认证状态
}
}
/// 登录
Future<void> login({
required String account, // 用户名或邮箱
required String password,
bool rememberMe = false,
}) async {
state = state.copyWith(isLoading: true, error: null);
try {
// 调用真实API
final authResponse = await _authService.login(
account: account,
password: password,
rememberMe: rememberMe,
);
// 保存token
await _storageService.saveToken(authResponse.token);
if (rememberMe && authResponse.refreshToken != null) {
await _storageService.saveRefreshToken(authResponse.refreshToken!);
}
// 更新状态
state = state.copyWith(
user: authResponse.user,
isAuthenticated: true,
isLoading: false,
);
} catch (e) {
state = state.copyWith(
isLoading: false,
error: e.toString(),
);
rethrow;
}
}
/// 注册
Future<void> register({
required String email,
required String password,
required String username,
required String nickname,
}) async {
state = state.copyWith(isLoading: true, error: null);
try {
// 调用真实API
final authResponse = await _authService.register(
email: email,
password: password,
username: username,
nickname: nickname,
);
// 保存token
await _storageService.saveToken(authResponse.token);
if (authResponse.refreshToken != null) {
await _storageService.saveRefreshToken(authResponse.refreshToken!);
}
// 更新状态
state = state.copyWith(
user: authResponse.user,
isAuthenticated: true,
isLoading: false,
);
} catch (e) {
state = state.copyWith(
isLoading: false,
error: e.toString(),
);
rethrow;
}
}
/// 登出
Future<void> logout() async {
state = state.copyWith(isLoading: true, error: null);
try {
// 模拟网络延迟
await Future.delayed(const Duration(milliseconds: 500));
await _storageService.clearTokens();
state = const AuthState();
} catch (e) {
state = state.copyWith(
isLoading: false,
error: e.toString(),
);
rethrow;
}
}
/// 忘记密码
Future<void> forgotPassword(String email) async {
state = state.copyWith(isLoading: true, error: null);
try {
// 模拟网络延迟
await Future.delayed(const Duration(milliseconds: 1000));
if (email.isEmpty) {
throw Exception('邮箱地址不能为空');
}
// 模拟发送重置邮件成功
state = state.copyWith(isLoading: false);
} catch (e) {
state = state.copyWith(
isLoading: false,
error: e.toString(),
);
rethrow;
}
}
/// 重置密码
Future<void> resetPassword({
required String token,
required String newPassword,
}) async {
state = state.copyWith(isLoading: true, error: null);
try {
// 模拟网络延迟
await Future.delayed(const Duration(milliseconds: 1000));
if (newPassword.length < 6) {
throw Exception('密码长度不能少于6位');
}
state = state.copyWith(isLoading: false);
} catch (e) {
state = state.copyWith(
isLoading: false,
error: e.toString(),
);
rethrow;
}
}
/// 更新用户信息
Future<void> updateProfile({
String? username,
String? email,
String? phone,
String? avatar,
}) async {
if (state.user == null) return;
state = state.copyWith(isLoading: true, error: null);
try {
// 模拟网络延迟
await Future.delayed(const Duration(milliseconds: 1000));
final updatedUser = state.user!.copyWith(
username: username ?? state.user!.username,
email: email ?? state.user!.email,
phone: phone ?? state.user!.phone,
avatar: avatar ?? state.user!.avatar,
updatedAt: DateTime.now(),
);
state = state.copyWith(
user: updatedUser,
isLoading: false,
);
} catch (e) {
state = state.copyWith(
isLoading: false,
error: e.toString(),
);
rethrow;
}
}
/// 修改密码
Future<void> changePassword({
required String currentPassword,
required String newPassword,
}) async {
state = state.copyWith(isLoading: true, error: null);
try {
// 模拟网络延迟
await Future.delayed(const Duration(milliseconds: 1000));
if (currentPassword.isEmpty || newPassword.isEmpty) {
throw Exception('当前密码和新密码不能为空');
}
if (newPassword.length < 6) {
throw Exception('新密码长度不能少于6位');
}
state = state.copyWith(isLoading: false);
} catch (e) {
state = state.copyWith(
isLoading: false,
error: e.toString(),
);
rethrow;
}
}
/// 清除错误
void clearError() {
state = state.copyWith(error: null);
}
}
/// 认证服务提供者
final authServiceProvider = Provider<AuthService>((ref) {
return AuthService(ApiClient.instance);
});
/// 存储服务提供者 - 改为同步Provider因为StorageService已在main中初始化
final storageServiceProvider = Provider<StorageService>((ref) {
// StorageService已经在main.dart中初始化直接获取实例
// 这里使用一个技巧通过Future.value包装已初始化的实例
throw UnimplementedError('Use storageServiceInstanceProvider instead');
});
/// 认证状态提供者 - 改为StateNotifierProvider以保持状态
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
final authService = ref.watch(authServiceProvider);
// 直接使用已初始化的StorageService实例
final storageService = StorageService.instance;
return AuthNotifier(authService, storageService);
});
/// 是否已认证的提供者
final isAuthenticatedProvider = Provider<bool>((ref) {
return ref.watch(authProvider).isAuthenticated;
});
/// 当前用户提供者
final currentUserProvider = Provider<User?>((ref) {
return ref.watch(authProvider).user;
});