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

191 lines
6.7 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';
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;
AuthNotifier(this._secureStorage) : 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';
// 检查账号是否已创建
final isAccountCreatedStr = await _secureStorage.read(key: StorageKeys.isAccountCreated);
final isAccountCreated = isAccountCreatedStr == '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';
// 获取用户序列号和推荐码(用于跳转到备份页面)
final userSerialNum = await _secureStorage.read(key: StorageKeys.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);
}
}
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
final secureStorage = ref.watch(secureStorageProvider);
return AuthNotifier(secureStorage);
});