refactor: 钱包状态轮询自动重试,移除手动重试按钮

设计原则:只要钱包不是 ready 状态,就持续轮询并自动重试生成
- 移除 failed 状态和重试按钮(用户无需手动操作)
- 非 ready 时自动调用 retryWalletGeneration API(幂等)
- 轮询间隔改为60秒(API 1-10分钟幂等)
- 只有 ready 时停止轮询

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-21 18:20:10 -08:00
parent ffd4fae0b6
commit 3e352dbcfe
3 changed files with 42 additions and 182 deletions

View File

@ -11,32 +11,27 @@ enum WalletGenerationStatus {
unknown, //
generating, //
ready, //
failed, //
}
///
class WalletStatusState {
final WalletGenerationStatus status;
final String? errorMessage;
final DateTime? lastChecked;
final bool isPolling;
const WalletStatusState({
this.status = WalletGenerationStatus.unknown,
this.errorMessage,
this.lastChecked,
this.isPolling = false,
});
WalletStatusState copyWith({
WalletGenerationStatus? status,
String? errorMessage,
DateTime? lastChecked,
bool? isPolling,
}) {
return WalletStatusState(
status: status ?? this.status,
errorMessage: errorMessage,
lastChecked: lastChecked ?? this.lastChecked,
isPolling: isPolling ?? this.isPolling,
);
@ -44,10 +39,14 @@ class WalletStatusState {
bool get isGenerating => status == WalletGenerationStatus.generating;
bool get isReady => status == WalletGenerationStatus.ready;
bool get isFailed => status == WalletGenerationStatus.failed;
}
///
///
/// ready
/// - 1-10
/// - ready
/// - ready retryWalletGeneration API
class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
final AccountService _accountService;
final SecureStorage _secureStorage;
@ -58,7 +57,7 @@ class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
///
///
/// 5
/// 60
Future<void> startPolling() async {
if (state.isPolling) {
debugPrint('[WalletStatusProvider] Already polling, skipping');
@ -69,17 +68,12 @@ class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
state = state.copyWith(isPolling: true);
//
await _checkWalletStatus();
await _checkAndRetryIfNeeded();
// 5
// 601-10
_pollingTimer?.cancel();
_pollingTimer = Timer.periodic(const Duration(seconds: 5), (_) async {
await _checkWalletStatus();
//
if (state.isReady || state.isFailed) {
stopPolling();
}
_pollingTimer = Timer.periodic(const Duration(seconds: 60), (_) async {
await _checkAndRetryIfNeeded();
});
}
@ -91,8 +85,8 @@ class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
state = state.copyWith(isPolling: false);
}
///
Future<void> _checkWalletStatus() async {
/// ready
Future<void> _checkAndRetryIfNeeded() async {
try {
debugPrint('[WalletStatusProvider] Checking wallet status...');
@ -112,62 +106,46 @@ class WalletStatusNotifier extends StateNotifier<WalletStatusState> {
debugPrint(
'[WalletStatusProvider] Wallet status: ${walletInfo.status}');
//
WalletGenerationStatus newStatus;
if (walletInfo.isReady) {
newStatus = WalletGenerationStatus.ready;
//
//
await _secureStorage.write(
key: StorageKeys.isWalletReady,
value: 'true',
);
debugPrint('[WalletStatusProvider] Wallet is ready, marked in storage');
} else if (walletInfo.isGenerating) {
newStatus = WalletGenerationStatus.generating;
} else if (walletInfo.isFailed) {
newStatus = WalletGenerationStatus.failed;
} else {
newStatus = WalletGenerationStatus.unknown;
}
debugPrint('[WalletStatusProvider] Wallet is ready, stopping polling');
state = state.copyWith(
status: newStatus,
lastChecked: DateTime.now(),
errorMessage: null,
);
state = state.copyWith(
status: WalletGenerationStatus.ready,
lastChecked: DateTime.now(),
);
stopPolling();
} else {
// ready API
debugPrint('[WalletStatusProvider] Wallet not ready, triggering retry...');
try {
await _accountService.retryWalletGeneration();
debugPrint('[WalletStatusProvider] Retry triggered successfully');
} catch (e) {
debugPrint('[WalletStatusProvider] Retry API call failed: $e');
//
}
state = state.copyWith(
status: WalletGenerationStatus.generating,
lastChecked: DateTime.now(),
);
}
} catch (e) {
debugPrint('[WalletStatusProvider] Error checking wallet status: $e');
//
state = state.copyWith(
errorMessage: e.toString(),
lastChecked: DateTime.now(),
);
}
}
///
Future<void> retryWalletGeneration() async {
try {
debugPrint('[WalletStatusProvider] Manually retrying wallet generation');
// API
await _accountService.retryWalletGeneration();
//
state = state.copyWith(
status: WalletGenerationStatus.generating,
errorMessage: null,
);
if (!state.isPolling) {
await startPolling();
}
} catch (e) {
debugPrint('[WalletStatusProvider] Error retrying wallet generation: $e');
state = state.copyWith(errorMessage: e.toString());
}
}
@override
void dispose() {
_pollingTimer?.cancel();

View File

@ -13,10 +13,9 @@ enum MonitorStatus {
///
enum WalletCreationStatus {
unknown, //
unknown, //
creating, // "创建账号审核中..."
ready, //
failed, //
}
/// -
@ -45,7 +44,6 @@ class _MiningPageState extends ConsumerState<MiningPage> {
//
WalletCreationStatus _walletStatus = WalletCreationStatus.unknown;
String? _walletError;
Timer? _walletPollingTimer;
@override
@ -170,19 +168,13 @@ class _MiningPageState extends ConsumerState<MiningPage> {
setState(() {
if (walletInfo.isReady) {
_walletStatus = WalletCreationStatus.ready;
_walletError = null;
//
_walletPollingTimer?.cancel();
debugPrint('[MiningPage] 钱包已就绪,停止轮询');
} else if (walletInfo.isFailed) {
_walletStatus = WalletCreationStatus.failed;
_walletError = '账号创建失败';
_walletPollingTimer?.cancel();
debugPrint('[MiningPage] 钱包创建失败');
} else {
// ready failedcreating
_walletStatus = WalletCreationStatus.creating;
_walletError = null;
debugPrint('[MiningPage] 钱包创建中...');
debugPrint('[MiningPage] 钱包创建中,继续轮询...');
}
});
} catch (e) {
@ -191,34 +183,6 @@ class _MiningPageState extends ConsumerState<MiningPage> {
}
}
///
Future<void> _retryWalletGeneration() async {
try {
debugPrint('[MiningPage] 手动重试钱包生成...');
final accountService = ref.read(accountServiceProvider);
await accountService.retryWalletGeneration();
if (!mounted) return;
//
setState(() {
_walletStatus = WalletCreationStatus.creating;
_walletError = null;
});
//
_walletPollingTimer?.cancel();
_startWalletPolling();
} catch (e) {
debugPrint('[MiningPage] 重试钱包生成失败: $e');
if (mounted) {
setState(() {
_walletError = '重试失败: $e';
});
}
}
}
///
void _showHelpInfo() {
showDialog(
@ -433,43 +397,6 @@ class _MiningPageState extends ConsumerState<MiningPage> {
),
],
)
else if (_walletStatus == WalletCreationStatus.failed)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_walletError ?? '账号创建失败',
style: const TextStyle(
fontSize: 16,
fontFamily: 'Inter',
fontWeight: FontWeight.w600,
color: Colors.red,
),
),
const SizedBox(height: 4),
GestureDetector(
onTap: _retryWalletGeneration,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: const Color(0xFF8B5A2B),
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'重试',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
],
)
else if (_walletStatus == WalletCreationStatus.ready)
Text(
'序列号$_serialNumber',

View File

@ -4079,52 +4079,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
);
}
//
if (walletStatus.isFailed) {
return Row(
children: [
const Icon(
Icons.error_outline,
size: 16,
color: Color(0xFFD32F2F),
),
const SizedBox(width: 8),
Text(
'钱包生成失败',
style: const TextStyle(
fontSize: 14,
fontFamily: 'Inter',
height: 1.5,
color: Color(0xFFD32F2F),
),
),
const SizedBox(width: 8),
GestureDetector(
onTap: () async {
await ref.read(walletStatusProvider.notifier).retryWalletGeneration();
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: const Color(0xFFD4AF37),
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'重试',
style: TextStyle(
fontSize: 12,
fontFamily: 'Inter',
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
),
),
],
);
}
// unknown状态"创建账号审核中..."
// unknown/generating状态"创建账号审核中..."
return Row(
children: [
const SizedBox(