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

View File

@ -13,10 +13,9 @@ enum MonitorStatus {
/// ///
enum WalletCreationStatus { enum WalletCreationStatus {
unknown, // unknown, //
creating, // "创建账号审核中..." creating, // "创建账号审核中..."
ready, // ready, //
failed, //
} }
/// - /// -
@ -45,7 +44,6 @@ class _MiningPageState extends ConsumerState<MiningPage> {
// //
WalletCreationStatus _walletStatus = WalletCreationStatus.unknown; WalletCreationStatus _walletStatus = WalletCreationStatus.unknown;
String? _walletError;
Timer? _walletPollingTimer; Timer? _walletPollingTimer;
@override @override
@ -170,19 +168,13 @@ class _MiningPageState extends ConsumerState<MiningPage> {
setState(() { setState(() {
if (walletInfo.isReady) { if (walletInfo.isReady) {
_walletStatus = WalletCreationStatus.ready; _walletStatus = WalletCreationStatus.ready;
_walletError = null;
// //
_walletPollingTimer?.cancel(); _walletPollingTimer?.cancel();
debugPrint('[MiningPage] 钱包已就绪,停止轮询'); debugPrint('[MiningPage] 钱包已就绪,停止轮询');
} else if (walletInfo.isFailed) {
_walletStatus = WalletCreationStatus.failed;
_walletError = '账号创建失败';
_walletPollingTimer?.cancel();
debugPrint('[MiningPage] 钱包创建失败');
} else { } else {
// ready failedcreating
_walletStatus = WalletCreationStatus.creating; _walletStatus = WalletCreationStatus.creating;
_walletError = null; debugPrint('[MiningPage] 钱包创建中,继续轮询...');
debugPrint('[MiningPage] 钱包创建中...');
} }
}); });
} catch (e) { } 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() { void _showHelpInfo() {
showDialog( 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) else if (_walletStatus == WalletCreationStatus.ready)
Text( Text(
'序列号$_serialNumber', '序列号$_serialNumber',

View File

@ -4079,52 +4079,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
); );
} }
// // unknown/generating状态"创建账号审核中..."
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状态"创建账号审核中..."
return Row( return Row(
children: [ children: [
const SizedBox( const SizedBox(