rwadurian/frontend/mobile-app/lib/features/auth/presentation/providers/auth_provider.dart

211 lines
7.6 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/storage/secure_storage.dart';
import '../../../../core/storage/storage_keys.dart';
import '../../../../core/di/injection_container.dart';
import '../../../../core/telemetry/telemetry_service.dart';
import '../../../../core/sentry/sentry_service.dart';
import '../../../../core/providers/notification_badge_provider.dart';
enum AuthStatus {
initial,
checking,
authenticated,
unauthenticated,
}
class AuthState {
final AuthStatus status;
final String? walletAddress;
final bool isWalletCreated;
final bool isFirstLaunch;
final bool hasSeenGuide;
final String? errorMessage;
// 新增:账号是否已创建(但钱包可能还未就绪)
final bool isAccountCreated;
// 新增:钱包是否已就绪
final bool isWalletReady;
// 新增:用户序列号(用于跳转到备份助记词页面)
final String? userSerialNum;
// 新增:推荐码
final String? referralCode;
const AuthState({
this.status = AuthStatus.initial,
this.walletAddress,
this.isWalletCreated = false,
this.isFirstLaunch = true,
this.hasSeenGuide = false,
this.errorMessage,
this.isAccountCreated = false,
this.isWalletReady = false,
this.userSerialNum,
this.referralCode,
});
AuthState copyWith({
AuthStatus? status,
String? walletAddress,
bool? isWalletCreated,
bool? isFirstLaunch,
bool? hasSeenGuide,
String? errorMessage,
bool? isAccountCreated,
bool? isWalletReady,
String? userSerialNum,
String? referralCode,
}) {
return AuthState(
status: status ?? this.status,
walletAddress: walletAddress ?? this.walletAddress,
isWalletCreated: isWalletCreated ?? this.isWalletCreated,
isFirstLaunch: isFirstLaunch ?? this.isFirstLaunch,
hasSeenGuide: hasSeenGuide ?? this.hasSeenGuide,
errorMessage: errorMessage,
isAccountCreated: isAccountCreated ?? this.isAccountCreated,
isWalletReady: isWalletReady ?? this.isWalletReady,
userSerialNum: userSerialNum ?? this.userSerialNum,
referralCode: referralCode ?? this.referralCode,
);
}
}
class AuthNotifier extends StateNotifier<AuthState> {
final SecureStorage _secureStorage;
final Ref _ref;
AuthNotifier(this._secureStorage, this._ref) : super(const AuthState());
Future<void> checkAuthStatus() async {
state = state.copyWith(status: AuthStatus.checking);
try {
// 检查是否首次启动
final isFirstLaunchStr = await _secureStorage.read(key: StorageKeys.isFirstLaunch);
final isFirstLaunch = isFirstLaunchStr == null || isFirstLaunchStr != 'false';
// 检查账号是否已创建
var isAccountCreatedStr = await _secureStorage.read(key: StorageKeys.isAccountCreated);
var isAccountCreated = isAccountCreatedStr == 'true';
// 修复:如果有 token 和 userSerialNum但 isAccountCreated 为 false自动修复
final accessToken = await _secureStorage.read(key: StorageKeys.accessToken);
final userSerialNum = await _secureStorage.read(key: StorageKeys.userSerialNum);
if (!isAccountCreated && accessToken != null && accessToken.isNotEmpty &&
userSerialNum != null && userSerialNum.isNotEmpty) {
// 自动修复:设置 isAccountCreated = true
await _secureStorage.write(key: StorageKeys.isAccountCreated, value: 'true');
isAccountCreated = true;
}
// 检查钱包是否已就绪
final isWalletReadyStr = await _secureStorage.read(key: StorageKeys.isWalletReady);
final isWalletReady = isWalletReadyStr == 'true';
// 检查助记词是否已备份
final isMnemonicBackedUpStr = await _secureStorage.read(key: StorageKeys.isMnemonicBackedUp);
final isMnemonicBackedUp = isMnemonicBackedUpStr == 'true';
// 获取推荐码(用于跳转到备份页面)
// 注意userSerialNum 已在上面读取过了
final referralCode = await _secureStorage.read(key: StorageKeys.referralCode);
// 旧版兼容:检查旧的 walletAddress 字段
final walletAddress = await _secureStorage.read(key: StorageKeys.walletAddress);
final hasLegacyWallet = walletAddress != null && walletAddress.isNotEmpty;
// 综合判断钱包是否已创建完成
// 1. 新版isWalletReady == true 且 isMnemonicBackedUp == true
// 2. 旧版兼容:有 walletAddress
final isWalletCreated = (isWalletReady && isMnemonicBackedUp) || hasLegacyWallet;
if (isWalletCreated) {
// 钱包已创建且备份完成,进入主页面
state = state.copyWith(
status: AuthStatus.authenticated,
walletAddress: walletAddress,
isWalletCreated: true,
isAccountCreated: true,
isWalletReady: true,
isFirstLaunch: false,
hasSeenGuide: true,
userSerialNum: userSerialNum,
referralCode: referralCode,
);
// 设置遥测服务的用户ID使用userSerialNum如D25121400005
if (userSerialNum != null && TelemetryService().isInitialized) {
TelemetryService().setUserId(userSerialNum);
}
// 设置 Sentry 用户信息
if (userSerialNum != null && SentryService().isInitialized) {
SentryService().setUser(userId: userSerialNum);
}
} else if (isAccountCreated) {
// 账号已创建但钱包未完成(可能正在生成或未备份)
state = state.copyWith(
status: AuthStatus.unauthenticated,
isWalletCreated: false,
isAccountCreated: true,
isWalletReady: isWalletReady,
isFirstLaunch: false,
hasSeenGuide: true,
userSerialNum: userSerialNum,
referralCode: referralCode,
);
} else {
// 账号未创建
state = state.copyWith(
status: AuthStatus.unauthenticated,
isWalletCreated: false,
isAccountCreated: false,
isWalletReady: false,
isFirstLaunch: isFirstLaunch,
hasSeenGuide: !isFirstLaunch,
);
}
} catch (e) {
state = state.copyWith(
status: AuthStatus.unauthenticated,
errorMessage: e.toString(),
);
}
}
/// 标记已查看向导页
Future<void> markGuideAsSeen() async {
await _secureStorage.write(key: StorageKeys.isFirstLaunch, value: 'false');
state = state.copyWith(
isFirstLaunch: false,
hasSeenGuide: true,
);
}
Future<void> saveWallet(String walletAddress, String privateKey) async {
await _secureStorage.write(key: StorageKeys.walletAddress, value: walletAddress);
await _secureStorage.write(key: StorageKeys.privateKey, value: privateKey);
state = state.copyWith(
status: AuthStatus.authenticated,
walletAddress: walletAddress,
isWalletCreated: true,
);
}
Future<void> logout() async {
await _secureStorage.deleteAll();
state = const AuthState(status: AuthStatus.unauthenticated);
// 清空未读通知数量
_ref.read(notificationBadgeProvider.notifier).clearCount();
}
/// 重新加载认证状态checkAuthStatus 的别名)
/// 用于注册/登录成功后刷新状态
Future<void> loadAuthState() async {
await checkAuthStatus();
}
}
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
final secureStorage = ref.watch(secureStorageProvider);
return AuthNotifier(secureStorage, ref);
});