312 lines
7.9 KiB
Dart
312 lines
7.9 KiB
Dart
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;
|
||
}); |