feat(mobile-app): add detailed debug logging for account creation flow
Add comprehensive debugPrint logging with [Tag] prefixes: - [AccountService]: API calls, storage operations, responses - [OnboardingPage]: account status check, creation flow - [BackupMnemonicPage]: wallet info loading, polling state Logging includes: - Request/response details with masked sensitive data - Stack traces for error handling - Polling count and timing for wallet generation - User interaction tracking 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
6150617c14
commit
37aab77e7a
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:io';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import '../network/api_client.dart';
|
||||
import '../storage/secure_storage.dart';
|
||||
|
|
@ -44,6 +45,10 @@ class DeviceHardwareInfo {
|
|||
if (sdkInt != null) 'sdkInt': sdkInt,
|
||||
if (isPhysicalDevice != null) 'isPhysicalDevice': isPhysicalDevice,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'DeviceHardwareInfo(brand: $brand, model: $model, platform: $platform, osVersion: $osVersion)';
|
||||
}
|
||||
|
||||
/// 创建账号请求
|
||||
|
|
@ -64,6 +69,10 @@ class CreateAccountRequest {
|
|||
if (inviterReferralCode != null)
|
||||
'inviterReferralCode': inviterReferralCode,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'CreateAccountRequest(deviceId: $deviceId, inviterReferralCode: $inviterReferralCode)';
|
||||
}
|
||||
|
||||
/// 创建账号响应 (新版 - 不含钱包信息)
|
||||
|
|
@ -85,6 +94,7 @@ class CreateAccountResponse {
|
|||
});
|
||||
|
||||
factory CreateAccountResponse.fromJson(Map<String, dynamic> json) {
|
||||
debugPrint('[AccountService] 解析 CreateAccountResponse: ${json.keys.toList()}');
|
||||
return CreateAccountResponse(
|
||||
userSerialNum: json['userSerialNum'] as int,
|
||||
referralCode: json['referralCode'] as String,
|
||||
|
|
@ -94,6 +104,10 @@ class CreateAccountResponse {
|
|||
refreshToken: json['refreshToken'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'CreateAccountResponse(userSerialNum: $userSerialNum, username: $username, referralCode: $referralCode)';
|
||||
}
|
||||
|
||||
/// 钱包信息响应
|
||||
|
|
@ -109,6 +123,7 @@ class WalletInfoResponse {
|
|||
});
|
||||
|
||||
factory WalletInfoResponse.fromJson(Map<String, dynamic> json) {
|
||||
debugPrint('[AccountService] 解析 WalletInfoResponse: status=${json['status']}');
|
||||
return WalletInfoResponse(
|
||||
status: json['status'] as String,
|
||||
walletAddresses: json['walletAddresses'] != null
|
||||
|
|
@ -122,6 +137,10 @@ class WalletInfoResponse {
|
|||
bool get isReady => status == 'ready';
|
||||
bool get isGenerating => status == 'generating';
|
||||
bool get isFailed => status == 'failed';
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'WalletInfoResponse(status: $status, hasAddresses: ${walletAddresses != null}, hasMnemonic: ${mnemonic != null})';
|
||||
}
|
||||
|
||||
/// 钱包地址
|
||||
|
|
@ -137,12 +156,23 @@ class WalletAddresses {
|
|||
});
|
||||
|
||||
factory WalletAddresses.fromJson(Map<String, dynamic> json) {
|
||||
debugPrint('[AccountService] 解析 WalletAddresses: kava=${_maskAddress(json['kava'])}, dst=${_maskAddress(json['dst'])}, bsc=${_maskAddress(json['bsc'])}');
|
||||
return WalletAddresses(
|
||||
kava: json['kava'] as String,
|
||||
dst: json['dst'] as String,
|
||||
bsc: json['bsc'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'WalletAddresses(kava: ${_maskAddress(kava)}, dst: ${_maskAddress(dst)}, bsc: ${_maskAddress(bsc)})';
|
||||
}
|
||||
|
||||
/// 遮蔽地址中间部分,用于日志输出
|
||||
String _maskAddress(String? address) {
|
||||
if (address == null || address.length <= 10) return address ?? 'null';
|
||||
return '${address.substring(0, 6)}...${address.substring(address.length - 4)}';
|
||||
}
|
||||
|
||||
/// 账号服务
|
||||
|
|
@ -152,29 +182,40 @@ class AccountService {
|
|||
final ApiClient _apiClient;
|
||||
final SecureStorage _secureStorage;
|
||||
|
||||
static const String _tag = '[AccountService]';
|
||||
|
||||
AccountService({
|
||||
required ApiClient apiClient,
|
||||
required SecureStorage secureStorage,
|
||||
}) : _apiClient = apiClient,
|
||||
_secureStorage = secureStorage;
|
||||
_secureStorage = secureStorage {
|
||||
debugPrint('$_tag 初始化完成');
|
||||
}
|
||||
|
||||
/// 获取设备唯一标识符
|
||||
///
|
||||
/// Android: 使用 Android ID (64位十六进制字符串)
|
||||
/// iOS: 使用 identifierForVendor
|
||||
Future<String> getDeviceId() async {
|
||||
debugPrint('$_tag getDeviceId() - 开始获取设备ID');
|
||||
final deviceInfoPlugin = DeviceInfoPlugin();
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
final info = await deviceInfoPlugin.androidInfo;
|
||||
return info.id; // Android ID
|
||||
final deviceId = info.id;
|
||||
debugPrint('$_tag getDeviceId() - Android ID: ${_maskAddress(deviceId)}');
|
||||
return deviceId;
|
||||
} else if (Platform.isIOS) {
|
||||
final info = await deviceInfoPlugin.iosInfo;
|
||||
return info.identifierForVendor ?? const Uuid().v4();
|
||||
final deviceId = info.identifierForVendor ?? const Uuid().v4();
|
||||
debugPrint('$_tag getDeviceId() - iOS identifierForVendor: ${_maskAddress(deviceId)}');
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
// 其他平台回退到 UUID
|
||||
return const Uuid().v4();
|
||||
final uuid = const Uuid().v4();
|
||||
debugPrint('$_tag getDeviceId() - 其他平台,使用 UUID: ${_maskAddress(uuid)}');
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/// 获取设备硬件信息
|
||||
|
|
@ -182,11 +223,12 @@ class AccountService {
|
|||
/// Android: 完整硬件信息
|
||||
/// iOS: 基本信息
|
||||
Future<DeviceHardwareInfo> getDeviceHardwareInfo() async {
|
||||
debugPrint('$_tag getDeviceHardwareInfo() - 开始获取设备硬件信息');
|
||||
final deviceInfoPlugin = DeviceInfoPlugin();
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
final info = await deviceInfoPlugin.androidInfo;
|
||||
return DeviceHardwareInfo(
|
||||
final hardwareInfo = DeviceHardwareInfo(
|
||||
brand: info.brand,
|
||||
manufacturer: info.manufacturer,
|
||||
model: info.model,
|
||||
|
|
@ -198,9 +240,11 @@ class AccountService {
|
|||
sdkInt: info.version.sdkInt,
|
||||
isPhysicalDevice: info.isPhysicalDevice,
|
||||
);
|
||||
debugPrint('$_tag getDeviceHardwareInfo() - Android: $hardwareInfo');
|
||||
return hardwareInfo;
|
||||
} else if (Platform.isIOS) {
|
||||
final info = await deviceInfoPlugin.iosInfo;
|
||||
return DeviceHardwareInfo(
|
||||
final hardwareInfo = DeviceHardwareInfo(
|
||||
brand: 'Apple',
|
||||
manufacturer: 'Apple',
|
||||
model: info.model,
|
||||
|
|
@ -209,9 +253,12 @@ class AccountService {
|
|||
platform: 'ios',
|
||||
isPhysicalDevice: info.isPhysicalDevice,
|
||||
);
|
||||
debugPrint('$_tag getDeviceHardwareInfo() - iOS: $hardwareInfo');
|
||||
return hardwareInfo;
|
||||
}
|
||||
|
||||
// 其他平台返回空信息
|
||||
debugPrint('$_tag getDeviceHardwareInfo() - 其他平台,返回空信息');
|
||||
return DeviceHardwareInfo();
|
||||
}
|
||||
|
||||
|
|
@ -221,37 +268,57 @@ class AccountService {
|
|||
Future<CreateAccountResponse> createAccount({
|
||||
String? inviterReferralCode,
|
||||
}) async {
|
||||
debugPrint('$_tag createAccount() - 开始创建账号');
|
||||
debugPrint('$_tag createAccount() - 邀请码: ${inviterReferralCode ?? "无"}');
|
||||
|
||||
try {
|
||||
// 获取设备ID (必填)
|
||||
final deviceId = await getDeviceId();
|
||||
debugPrint('$_tag createAccount() - 获取设备ID成功');
|
||||
|
||||
// 获取设备硬件信息 (可选)
|
||||
final deviceName = await getDeviceHardwareInfo();
|
||||
debugPrint('$_tag createAccount() - 获取设备硬件信息成功');
|
||||
|
||||
final request = CreateAccountRequest(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
inviterReferralCode: inviterReferralCode,
|
||||
);
|
||||
debugPrint('$_tag createAccount() - 请求参数: $request');
|
||||
|
||||
// 调用 API
|
||||
debugPrint('$_tag createAccount() - 调用 POST /user/auto-create');
|
||||
final response = await _apiClient.post(
|
||||
'/user/auto-create',
|
||||
data: CreateAccountRequest(
|
||||
deviceId: deviceId,
|
||||
deviceName: deviceName,
|
||||
inviterReferralCode: inviterReferralCode,
|
||||
).toJson(),
|
||||
data: request.toJson(),
|
||||
);
|
||||
debugPrint('$_tag createAccount() - API 响应状态码: ${response.statusCode}');
|
||||
|
||||
if (response.data == null) {
|
||||
debugPrint('$_tag createAccount() - 错误: API 返回空响应');
|
||||
throw const ApiException('创建账号失败: 空响应');
|
||||
}
|
||||
|
||||
debugPrint('$_tag createAccount() - 解析响应数据');
|
||||
final result = CreateAccountResponse.fromJson(
|
||||
response.data as Map<String, dynamic>,
|
||||
);
|
||||
debugPrint('$_tag createAccount() - 解析成功: $result');
|
||||
|
||||
// 保存账号数据到安全存储
|
||||
debugPrint('$_tag createAccount() - 保存账号数据到安全存储');
|
||||
await _saveAccountData(result, deviceId);
|
||||
debugPrint('$_tag createAccount() - 账号数据保存成功');
|
||||
|
||||
debugPrint('$_tag createAccount() - 账号创建完成');
|
||||
return result;
|
||||
} on ApiException {
|
||||
} on ApiException catch (e) {
|
||||
debugPrint('$_tag createAccount() - API 异常: $e');
|
||||
rethrow;
|
||||
} catch (e) {
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('$_tag createAccount() - 未知异常: $e');
|
||||
debugPrint('$_tag createAccount() - 堆栈: $stackTrace');
|
||||
throw ApiException('创建账号失败: $e');
|
||||
}
|
||||
}
|
||||
|
|
@ -260,26 +327,43 @@ class AccountService {
|
|||
///
|
||||
/// 用 userSerialNum 查询钱包生成状态和助记词
|
||||
Future<WalletInfoResponse> getWalletInfo(int userSerialNum) async {
|
||||
debugPrint('$_tag getWalletInfo() - 开始获取钱包信息');
|
||||
debugPrint('$_tag getWalletInfo() - userSerialNum: $userSerialNum');
|
||||
|
||||
try {
|
||||
debugPrint('$_tag getWalletInfo() - 调用 GET /user/$userSerialNum/wallet');
|
||||
final response = await _apiClient.get('/user/$userSerialNum/wallet');
|
||||
debugPrint('$_tag getWalletInfo() - API 响应状态码: ${response.statusCode}');
|
||||
|
||||
if (response.data == null) {
|
||||
debugPrint('$_tag getWalletInfo() - 错误: API 返回空响应');
|
||||
throw const ApiException('获取钱包信息失败: 空响应');
|
||||
}
|
||||
|
||||
debugPrint('$_tag getWalletInfo() - 解析响应数据');
|
||||
final result = WalletInfoResponse.fromJson(
|
||||
response.data as Map<String, dynamic>,
|
||||
);
|
||||
debugPrint('$_tag getWalletInfo() - 解析成功: $result');
|
||||
|
||||
// 如果钱包已就绪,保存钱包地址和助记词
|
||||
if (result.isReady) {
|
||||
debugPrint('$_tag getWalletInfo() - 钱包已就绪,保存钱包数据');
|
||||
await _saveWalletData(result);
|
||||
debugPrint('$_tag getWalletInfo() - 钱包数据保存成功');
|
||||
} else if (result.isGenerating) {
|
||||
debugPrint('$_tag getWalletInfo() - 钱包生成中,需要继续轮询');
|
||||
} else if (result.isFailed) {
|
||||
debugPrint('$_tag getWalletInfo() - 钱包生成失败');
|
||||
}
|
||||
|
||||
return result;
|
||||
} on ApiException {
|
||||
} on ApiException catch (e) {
|
||||
debugPrint('$_tag getWalletInfo() - API 异常: $e');
|
||||
rethrow;
|
||||
} catch (e) {
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('$_tag getWalletInfo() - 未知异常: $e');
|
||||
debugPrint('$_tag getWalletInfo() - 堆栈: $stackTrace');
|
||||
throw ApiException('获取钱包信息失败: $e');
|
||||
}
|
||||
}
|
||||
|
|
@ -289,150 +373,218 @@ class AccountService {
|
|||
CreateAccountResponse response,
|
||||
String deviceId,
|
||||
) async {
|
||||
debugPrint('$_tag _saveAccountData() - 开始保存账号数据');
|
||||
|
||||
// 保存用户序列号
|
||||
debugPrint('$_tag _saveAccountData() - 保存 userSerialNum: ${response.userSerialNum}');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.userSerialNum,
|
||||
value: response.userSerialNum.toString(),
|
||||
);
|
||||
|
||||
debugPrint('$_tag _saveAccountData() - 保存 referralCode: ${response.referralCode}');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.referralCode,
|
||||
value: response.referralCode,
|
||||
);
|
||||
|
||||
// 保存用户信息
|
||||
debugPrint('$_tag _saveAccountData() - 保存 username: ${response.username}');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.username,
|
||||
value: response.username,
|
||||
);
|
||||
|
||||
debugPrint('$_tag _saveAccountData() - 保存 avatarSvg (长度: ${response.avatarSvg.length})');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.avatarSvg,
|
||||
value: response.avatarSvg,
|
||||
);
|
||||
|
||||
// 保存 Token
|
||||
debugPrint('$_tag _saveAccountData() - 保存 accessToken (长度: ${response.accessToken.length})');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.accessToken,
|
||||
value: response.accessToken,
|
||||
);
|
||||
|
||||
debugPrint('$_tag _saveAccountData() - 保存 refreshToken (长度: ${response.refreshToken.length})');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.refreshToken,
|
||||
value: response.refreshToken,
|
||||
);
|
||||
|
||||
// 保存设备 ID
|
||||
debugPrint('$_tag _saveAccountData() - 保存 deviceId: ${_maskAddress(deviceId)}');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.deviceId,
|
||||
value: deviceId,
|
||||
);
|
||||
|
||||
// 标记账号已创建
|
||||
debugPrint('$_tag _saveAccountData() - 标记账号已创建');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.isAccountCreated,
|
||||
value: 'true',
|
||||
);
|
||||
|
||||
debugPrint('$_tag _saveAccountData() - 账号数据保存完成');
|
||||
}
|
||||
|
||||
/// 保存钱包数据
|
||||
Future<void> _saveWalletData(WalletInfoResponse response) async {
|
||||
debugPrint('$_tag _saveWalletData() - 开始保存钱包数据');
|
||||
|
||||
if (response.walletAddresses != null) {
|
||||
debugPrint('$_tag _saveWalletData() - 保存 BSC 地址: ${_maskAddress(response.walletAddresses!.bsc)}');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.walletAddressBsc,
|
||||
value: response.walletAddresses!.bsc,
|
||||
);
|
||||
|
||||
debugPrint('$_tag _saveWalletData() - 保存 KAVA 地址: ${_maskAddress(response.walletAddresses!.kava)}');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.walletAddressKava,
|
||||
value: response.walletAddresses!.kava,
|
||||
);
|
||||
|
||||
debugPrint('$_tag _saveWalletData() - 保存 DST 地址: ${_maskAddress(response.walletAddresses!.dst)}');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.walletAddressDst,
|
||||
value: response.walletAddresses!.dst,
|
||||
);
|
||||
} else {
|
||||
debugPrint('$_tag _saveWalletData() - 警告: walletAddresses 为空');
|
||||
}
|
||||
|
||||
if (response.mnemonic != null && response.mnemonic!.isNotEmpty) {
|
||||
final wordCount = response.mnemonic!.split(' ').length;
|
||||
debugPrint('$_tag _saveWalletData() - 保存助记词 ($wordCount 个单词)');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.mnemonic,
|
||||
value: response.mnemonic!,
|
||||
);
|
||||
} else {
|
||||
debugPrint('$_tag _saveWalletData() - 警告: mnemonic 为空');
|
||||
}
|
||||
|
||||
// 标记钱包已就绪
|
||||
debugPrint('$_tag _saveWalletData() - 标记钱包已就绪');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.isWalletReady,
|
||||
value: 'true',
|
||||
);
|
||||
|
||||
debugPrint('$_tag _saveWalletData() - 钱包数据保存完成');
|
||||
}
|
||||
|
||||
/// 检查是否已创建账号
|
||||
Future<bool> hasAccount() async {
|
||||
debugPrint('$_tag hasAccount() - 检查账号是否已创建');
|
||||
final isCreated =
|
||||
await _secureStorage.read(key: StorageKeys.isAccountCreated);
|
||||
return isCreated == 'true';
|
||||
final result = isCreated == 'true';
|
||||
debugPrint('$_tag hasAccount() - 结果: $result');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 检查钱包是否已就绪
|
||||
Future<bool> isWalletReady() async {
|
||||
debugPrint('$_tag isWalletReady() - 检查钱包是否已就绪');
|
||||
final isReady = await _secureStorage.read(key: StorageKeys.isWalletReady);
|
||||
return isReady == 'true';
|
||||
final result = isReady == 'true';
|
||||
debugPrint('$_tag isWalletReady() - 结果: $result');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 获取用户序列号
|
||||
Future<int?> getUserSerialNum() async {
|
||||
debugPrint('$_tag getUserSerialNum() - 获取用户序列号');
|
||||
final serialNum =
|
||||
await _secureStorage.read(key: StorageKeys.userSerialNum);
|
||||
return serialNum != null ? int.tryParse(serialNum) : null;
|
||||
final result = serialNum != null ? int.tryParse(serialNum) : null;
|
||||
debugPrint('$_tag getUserSerialNum() - 结果: $result');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 获取用户名
|
||||
Future<String?> getUsername() async {
|
||||
return _secureStorage.read(key: StorageKeys.username);
|
||||
debugPrint('$_tag getUsername() - 获取用户名');
|
||||
final result = await _secureStorage.read(key: StorageKeys.username);
|
||||
debugPrint('$_tag getUsername() - 结果: $result');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 获取头像 SVG
|
||||
Future<String?> getAvatarSvg() async {
|
||||
return _secureStorage.read(key: StorageKeys.avatarSvg);
|
||||
debugPrint('$_tag getAvatarSvg() - 获取头像 SVG');
|
||||
final result = await _secureStorage.read(key: StorageKeys.avatarSvg);
|
||||
debugPrint('$_tag getAvatarSvg() - 结果长度: ${result?.length ?? 0}');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 获取推荐码
|
||||
Future<String?> getReferralCode() async {
|
||||
return _secureStorage.read(key: StorageKeys.referralCode);
|
||||
debugPrint('$_tag getReferralCode() - 获取推荐码');
|
||||
final result = await _secureStorage.read(key: StorageKeys.referralCode);
|
||||
debugPrint('$_tag getReferralCode() - 结果: $result');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 获取钱包地址 (从本地存储)
|
||||
Future<WalletAddresses?> getWalletAddresses() async {
|
||||
debugPrint('$_tag getWalletAddresses() - 获取钱包地址');
|
||||
final bsc = await _secureStorage.read(key: StorageKeys.walletAddressBsc);
|
||||
final kava = await _secureStorage.read(key: StorageKeys.walletAddressKava);
|
||||
final dst = await _secureStorage.read(key: StorageKeys.walletAddressDst);
|
||||
|
||||
if (bsc == null || kava == null || dst == null) {
|
||||
debugPrint('$_tag getWalletAddresses() - 钱包地址不完整');
|
||||
return null;
|
||||
}
|
||||
|
||||
return WalletAddresses(kava: kava, dst: dst, bsc: bsc);
|
||||
final result = WalletAddresses(kava: kava, dst: dst, bsc: bsc);
|
||||
debugPrint('$_tag getWalletAddresses() - 结果: $result');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 获取助记词 (从本地存储)
|
||||
Future<String?> getMnemonic() async {
|
||||
return _secureStorage.read(key: StorageKeys.mnemonic);
|
||||
debugPrint('$_tag getMnemonic() - 获取助记词');
|
||||
final result = await _secureStorage.read(key: StorageKeys.mnemonic);
|
||||
if (result != null) {
|
||||
final wordCount = result.split(' ').length;
|
||||
debugPrint('$_tag getMnemonic() - 获取到 $wordCount 个单词');
|
||||
} else {
|
||||
debugPrint('$_tag getMnemonic() - 未找到助记词');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 标记助记词已备份
|
||||
Future<void> markMnemonicBackedUp() async {
|
||||
debugPrint('$_tag markMnemonicBackedUp() - 标记助记词已备份');
|
||||
await _secureStorage.write(
|
||||
key: StorageKeys.isMnemonicBackedUp,
|
||||
value: 'true',
|
||||
);
|
||||
debugPrint('$_tag markMnemonicBackedUp() - 完成');
|
||||
}
|
||||
|
||||
/// 检查助记词是否已备份
|
||||
Future<bool> isMnemonicBackedUp() async {
|
||||
debugPrint('$_tag isMnemonicBackedUp() - 检查助记词是否已备份');
|
||||
final isBackedUp =
|
||||
await _secureStorage.read(key: StorageKeys.isMnemonicBackedUp);
|
||||
return isBackedUp == 'true';
|
||||
final result = isBackedUp == 'true';
|
||||
debugPrint('$_tag isMnemonicBackedUp() - 结果: $result');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// 登出
|
||||
Future<void> logout() async {
|
||||
debugPrint('$_tag logout() - 开始登出,清除所有数据');
|
||||
await _secureStorage.deleteAll();
|
||||
debugPrint('$_tag logout() - 登出完成');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,27 +54,41 @@ class _BackupMnemonicPageState extends ConsumerState<BackupMnemonicPage> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
debugPrint('[BackupMnemonicPage] initState - userSerialNum: ${widget.userSerialNum}, referralCode: ${widget.referralCode}');
|
||||
_loadWalletInfo();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
debugPrint('[BackupMnemonicPage] dispose - 取消轮询定时器');
|
||||
_pollTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/// 加载钱包信息
|
||||
Future<void> _loadWalletInfo() async {
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - 开始加载钱包信息, userSerialNum: ${widget.userSerialNum}');
|
||||
try {
|
||||
final accountService = ref.read(accountServiceProvider);
|
||||
|
||||
// 调用 API 获取钱包信息
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - 调用 accountService.getWalletInfo()');
|
||||
final response = await accountService.getWalletInfo(widget.userSerialNum);
|
||||
|
||||
if (!mounted) return;
|
||||
if (!mounted) {
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - Widget已卸载,忽略响应');
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - 响应状态: ${response.status}, isReady: ${response.isReady}, isGenerating: ${response.isGenerating}, isFailed: ${response.isFailed}');
|
||||
|
||||
if (response.isReady) {
|
||||
// 钱包已就绪
|
||||
final wordCount = response.mnemonic?.split(' ').length ?? 0;
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - 钱包就绪! 助记词数量: $wordCount');
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - KAVA: ${_maskAddress(response.walletAddresses?.kava)}');
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - DST: ${_maskAddress(response.walletAddresses?.dst)}');
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - BSC: ${_maskAddress(response.walletAddresses?.bsc)}');
|
||||
setState(() {
|
||||
_walletInfo = response;
|
||||
_mnemonicWords = response.mnemonic?.split(' ') ?? [];
|
||||
|
|
@ -86,6 +100,7 @@ class _BackupMnemonicPageState extends ConsumerState<BackupMnemonicPage> {
|
|||
});
|
||||
} else if (response.isGenerating) {
|
||||
// 钱包生成中,轮询等待
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - 钱包生成中,开始轮询...');
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_errorMessage = null;
|
||||
|
|
@ -93,13 +108,15 @@ class _BackupMnemonicPageState extends ConsumerState<BackupMnemonicPage> {
|
|||
_startPolling();
|
||||
} else if (response.isFailed) {
|
||||
// 钱包生成失败
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - 钱包生成失败');
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
_errorMessage = '钱包生成失败,请稍后重试';
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('加载钱包信息失败: $e');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - 异常: $e');
|
||||
debugPrint('[BackupMnemonicPage] _loadWalletInfo - 堆栈: $stackTrace');
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
|
|
@ -109,23 +126,44 @@ class _BackupMnemonicPageState extends ConsumerState<BackupMnemonicPage> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 脱敏地址显示 (用于日志)
|
||||
String _maskAddress(String? address) {
|
||||
if (address == null || address.length < 10) return address ?? 'null';
|
||||
return '${address.substring(0, 6)}...${address.substring(address.length - 4)}';
|
||||
}
|
||||
|
||||
/// 开始轮询
|
||||
int _pollCount = 0;
|
||||
void _startPolling() {
|
||||
_pollTimer?.cancel();
|
||||
_pollCount = 0;
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - 启动轮询定时器 (每2秒)');
|
||||
_pollTimer = Timer.periodic(const Duration(seconds: 2), (timer) async {
|
||||
_pollCount++;
|
||||
if (!mounted) {
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - Widget已卸载,取消轮询');
|
||||
timer.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - 第 $_pollCount 次轮询...');
|
||||
|
||||
try {
|
||||
final accountService = ref.read(accountServiceProvider);
|
||||
final response = await accountService.getWalletInfo(widget.userSerialNum);
|
||||
|
||||
if (!mounted) return;
|
||||
if (!mounted) {
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - Widget已卸载,忽略响应');
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - 轮询响应状态: ${response.status}');
|
||||
|
||||
if (response.isReady) {
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - 钱包就绪! 停止轮询 (共轮询 $_pollCount 次)');
|
||||
timer.cancel();
|
||||
final wordCount = response.mnemonic?.split(' ').length ?? 0;
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - 助记词数量: $wordCount');
|
||||
setState(() {
|
||||
_walletInfo = response;
|
||||
_mnemonicWords = response.mnemonic?.split(' ') ?? [];
|
||||
|
|
@ -136,22 +174,25 @@ class _BackupMnemonicPageState extends ConsumerState<BackupMnemonicPage> {
|
|||
_errorMessage = null;
|
||||
});
|
||||
} else if (response.isFailed) {
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - 钱包生成失败,停止轮询');
|
||||
timer.cancel();
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
_errorMessage = '钱包生成失败,请稍后重试';
|
||||
});
|
||||
} else {
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - 仍在生成中,继续轮询...');
|
||||
}
|
||||
// 如果仍在生成中,继续轮询
|
||||
} catch (e) {
|
||||
// 忽略轮询中的错误,继续尝试
|
||||
debugPrint('轮询钱包信息出错: $e');
|
||||
debugPrint('[BackupMnemonicPage] _startPolling - 轮询出错 (继续重试): $e');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// 复制全部助记词
|
||||
void _copyAllMnemonic() {
|
||||
debugPrint('[BackupMnemonicPage] _copyAllMnemonic - 复制助记词到剪贴板');
|
||||
final mnemonicText = _mnemonicWords.join(' ');
|
||||
Clipboard.setData(ClipboardData(text: mnemonicText));
|
||||
_showCopySuccess('助记词已复制到剪贴板');
|
||||
|
|
@ -159,6 +200,7 @@ class _BackupMnemonicPageState extends ConsumerState<BackupMnemonicPage> {
|
|||
|
||||
/// 复制地址
|
||||
void _copyAddress(String address, String label) {
|
||||
debugPrint('[BackupMnemonicPage] _copyAddress - 复制 $label: ${_maskAddress(address)}');
|
||||
Clipboard.setData(ClipboardData(text: address));
|
||||
_showCopySuccess('$label 已复制');
|
||||
}
|
||||
|
|
@ -183,12 +225,17 @@ class _BackupMnemonicPageState extends ConsumerState<BackupMnemonicPage> {
|
|||
|
||||
/// 下载助记词备份文件
|
||||
Future<void> _downloadMnemonic() async {
|
||||
if (_isDownloading || _mnemonicWords.isEmpty) return;
|
||||
debugPrint('[BackupMnemonicPage] _downloadMnemonic - 开始下载备份文件');
|
||||
if (_isDownloading || _mnemonicWords.isEmpty) {
|
||||
debugPrint('[BackupMnemonicPage] _downloadMnemonic - 跳过: isDownloading=$_isDownloading, wordsEmpty=${_mnemonicWords.isEmpty}');
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _isDownloading = true);
|
||||
|
||||
try {
|
||||
// 获取临时目录
|
||||
debugPrint('[BackupMnemonicPage] _downloadMnemonic - 获取临时目录');
|
||||
final directory = await getTemporaryDirectory();
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final file = File('${directory.path}/mnemonic_backup_$timestamp.txt');
|
||||
|
|
@ -229,11 +276,13 @@ ${DateTime.now().toString()}
|
|||
''';
|
||||
|
||||
// 写入文件
|
||||
debugPrint('[BackupMnemonicPage] _downloadMnemonic - 写入文件: ${file.path}');
|
||||
await file.writeAsString(content);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
// 分享文件
|
||||
debugPrint('[BackupMnemonicPage] _downloadMnemonic - 调用分享');
|
||||
await Share.shareXFiles(
|
||||
[XFile(file.path)],
|
||||
subject: 'RWA 助记词备份',
|
||||
|
|
@ -241,9 +290,13 @@ ${DateTime.now().toString()}
|
|||
|
||||
// 删除临时文件
|
||||
if (await file.exists()) {
|
||||
debugPrint('[BackupMnemonicPage] _downloadMnemonic - 删除临时文件');
|
||||
await file.delete();
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[BackupMnemonicPage] _downloadMnemonic - 下载完成');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[BackupMnemonicPage] _downloadMnemonic - 下载失败: $e');
|
||||
debugPrint('[BackupMnemonicPage] _downloadMnemonic - 堆栈: $stackTrace');
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
|
|
@ -260,7 +313,9 @@ ${DateTime.now().toString()}
|
|||
|
||||
/// 确认已备份,跳转到确认备份页面进行验证
|
||||
void _confirmBackup() {
|
||||
debugPrint('[BackupMnemonicPage] _confirmBackup - 用户点击确认备份');
|
||||
if (_mnemonicWords.isEmpty || _kavaAddress == null) {
|
||||
debugPrint('[BackupMnemonicPage] _confirmBackup - 钱包信息不完整: words=${_mnemonicWords.length}, kavaAddress=${_kavaAddress != null}');
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('钱包信息不完整,请等待加载完成'),
|
||||
|
|
@ -270,6 +325,7 @@ ${DateTime.now().toString()}
|
|||
return;
|
||||
}
|
||||
|
||||
debugPrint('[BackupMnemonicPage] _confirmBackup - 跳转到验证页面, userSerialNum: ${widget.userSerialNum}');
|
||||
// 跳转到确认备份页面
|
||||
context.push(
|
||||
RoutePaths.verifyMnemonic,
|
||||
|
|
@ -286,6 +342,7 @@ ${DateTime.now().toString()}
|
|||
|
||||
/// 返回上一步
|
||||
void _goBack() {
|
||||
debugPrint('[BackupMnemonicPage] _goBack - 用户返回上一步');
|
||||
context.pop();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,24 +33,30 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
debugPrint('[OnboardingPage] initState - 检查账号状态');
|
||||
_checkAccountStatus();
|
||||
}
|
||||
|
||||
/// 检查账号是否已创建
|
||||
Future<void> _checkAccountStatus() async {
|
||||
debugPrint('[OnboardingPage] _checkAccountStatus - 开始检查');
|
||||
try {
|
||||
final accountService = ref.read(accountServiceProvider);
|
||||
|
||||
// 检查是否已创建账号
|
||||
final hasAccount = await accountService.hasAccount();
|
||||
debugPrint('[OnboardingPage] _checkAccountStatus - hasAccount: $hasAccount');
|
||||
|
||||
if (hasAccount) {
|
||||
// 读取已保存的账号数据
|
||||
debugPrint('[OnboardingPage] _checkAccountStatus - 读取已保存账号数据');
|
||||
final userSerialNum = await accountService.getUserSerialNum();
|
||||
final username = await accountService.getUsername();
|
||||
final avatarSvg = await accountService.getAvatarSvg();
|
||||
final referralCode = await accountService.getReferralCode();
|
||||
|
||||
debugPrint('[OnboardingPage] _checkAccountStatus - userSerialNum: $userSerialNum, username: $username');
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isAccountCreated = true;
|
||||
|
|
@ -64,6 +70,7 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
});
|
||||
}
|
||||
} else {
|
||||
debugPrint('[OnboardingPage] _checkAccountStatus - 账号未创建');
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isAccountCreated = false;
|
||||
|
|
@ -71,8 +78,9 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('检查账号状态失败: $e');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[OnboardingPage] _checkAccountStatus - 异常: $e');
|
||||
debugPrint('[OnboardingPage] _checkAccountStatus - 堆栈: $stackTrace');
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isAccountCreated = false;
|
||||
|
|
@ -86,7 +94,9 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
///
|
||||
/// 调用后端 API 快速创建账号(不含钱包信息)
|
||||
Future<void> _createAccount() async {
|
||||
debugPrint('[OnboardingPage] _createAccount - 用户点击创建账号');
|
||||
if (!_isAgreed) {
|
||||
debugPrint('[OnboardingPage] _createAccount - 未同意协议,显示提示');
|
||||
_showAgreementTip();
|
||||
return;
|
||||
}
|
||||
|
|
@ -100,13 +110,17 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
final accountService = ref.read(accountServiceProvider);
|
||||
|
||||
// 调用后端 API 创建账号
|
||||
debugPrint('开始创建账号...');
|
||||
debugPrint('[OnboardingPage] _createAccount - 调用 accountService.createAccount()');
|
||||
final response = await accountService.createAccount();
|
||||
debugPrint('账号创建成功: 序列号=${response.userSerialNum}, 用户名=${response.username}');
|
||||
debugPrint('[OnboardingPage] _createAccount - 成功! 序列号=${response.userSerialNum}, 用户名=${response.username}');
|
||||
|
||||
if (!mounted) return;
|
||||
if (!mounted) {
|
||||
debugPrint('[OnboardingPage] _createAccount - Widget已卸载,忽略响应');
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
debugPrint('[OnboardingPage] _createAccount - 更新本地状态');
|
||||
setState(() {
|
||||
_isAccountCreated = true;
|
||||
_userSerialNum = response.userSerialNum;
|
||||
|
|
@ -116,6 +130,7 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
});
|
||||
|
||||
// 跳转到备份助记词页面
|
||||
debugPrint('[OnboardingPage] _createAccount - 跳转到备份助记词页面');
|
||||
context.push(
|
||||
RoutePaths.backupMnemonic,
|
||||
extra: BackupMnemonicParams(
|
||||
|
|
@ -123,8 +138,9 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
referralCode: response.referralCode,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('创建账号失败: $e');
|
||||
} catch (e, stackTrace) {
|
||||
debugPrint('[OnboardingPage] _createAccount - 创建失败: $e');
|
||||
debugPrint('[OnboardingPage] _createAccount - 堆栈: $stackTrace');
|
||||
if (!mounted) return;
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
|
|
@ -171,7 +187,9 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
|
||||
/// 跳转到备份助记词页面(账号已创建的情况)
|
||||
void _goToBackupMnemonic() {
|
||||
debugPrint('[OnboardingPage] _goToBackupMnemonic - 跳转到备份页面');
|
||||
if (_userSerialNum == null) {
|
||||
debugPrint('[OnboardingPage] _goToBackupMnemonic - userSerialNum为空,显示错误');
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('账号数据不完整,请重新创建'),
|
||||
|
|
@ -181,6 +199,7 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
return;
|
||||
}
|
||||
|
||||
debugPrint('[OnboardingPage] _goToBackupMnemonic - userSerialNum: $_userSerialNum');
|
||||
context.push(
|
||||
RoutePaths.backupMnemonic,
|
||||
extra: BackupMnemonicParams(
|
||||
|
|
@ -192,6 +211,7 @@ class _OnboardingPageState extends ConsumerState<OnboardingPage> {
|
|||
|
||||
/// 处理按钮点击
|
||||
void _handleButtonTap() {
|
||||
debugPrint('[OnboardingPage] _handleButtonTap - isAccountCreated: $_isAccountCreated');
|
||||
if (_isAccountCreated) {
|
||||
// 账号已创建,跳转到备份页面
|
||||
_goToBackupMnemonic();
|
||||
|
|
|
|||
Loading…
Reference in New Issue