import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/l10n/app_localizations.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/utils/number_format.dart'; import '../../../data/models/asset/withdraw_record.dart'; import '../../../providers/withdraw_provider.dart'; import '../../widgets/common/app_refresh_indicator.dart'; class WithdrawHistoryScreen extends ConsumerStatefulWidget { const WithdrawHistoryScreen({super.key}); @override ConsumerState createState() => _WithdrawHistoryScreenState(); } class _WithdrawHistoryScreenState extends ConsumerState { @override void initState() { super.initState(); Future.microtask(() { ref.read(withdrawHistoryProvider.notifier).refresh(); }); } @override Widget build(BuildContext context) { final state = ref.watch(withdrawHistoryProvider); final notifier = ref.read(withdrawHistoryProvider.notifier); final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( // 原型:灰色页面背景,item 白色卡片浮于上 backgroundColor: isDark ? AppColors.darkBg : AppColors.lightBgSecondary, appBar: AppBar( backgroundColor: isDark ? AppColors.darkBg : AppColors.lightBg, leading: IconButton( icon: const Icon(Icons.chevron_left, size: 28), onPressed: () => context.pop(), ), title: Text(AppLocalizations.of(context)!.withdrawRecord, style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w600)), centerTitle: true, ), body: _buildBody(context, state, notifier), ); } Widget _buildBody(BuildContext context, WithdrawHistoryState state, WithdrawHistoryNotifier notifier) { final cs = Theme.of(context).colorScheme; if (state.isLoading && state.records.isEmpty) { return const Center(child: CircularProgressIndicator()); } if (state.errorMessage != null && state.records.isEmpty) { return AppRefreshIndicator( onRefresh: notifier.refresh, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const SizedBox(height: 120), Text(state.errorMessage!, style: TextStyle( color: cs.onSurface.withAlpha(153), fontSize: 14)), const SizedBox(height: 16), ElevatedButton( onPressed: notifier.refresh, child: Text(AppLocalizations.of(context)!.retry)), ], ), ), ), ); } if (state.records.isEmpty) { return AppRefreshIndicator( onRefresh: notifier.refresh, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: Center( child: Padding( padding: const EdgeInsets.symmetric(vertical: 120), child: Text(AppLocalizations.of(context)!.noRecord, style: TextStyle( color: cs.onSurface.withAlpha(120), fontSize: 14)), ), ), ), ); } return AppRefreshIndicator( onRefresh: notifier.refresh, child: NotificationListener( onNotification: (n) { if (n is ScrollEndNotification && n.metrics.pixels >= n.metrics.maxScrollExtent - 100) { notifier.loadMore(); } return false; }, child: ListView.builder( padding: const EdgeInsets.fromLTRB(16, 12, 16, 32), itemCount: state.records.length + (state.hasMore ? 1 : 0), itemBuilder: (_, i) { if (i >= state.records.length) { return const Padding( padding: EdgeInsets.symmetric(vertical: 16), child: Center( child: CircularProgressIndicator(strokeWidth: 2)), ); } final record = state.records[i]; return _RecordItem( record: record, onCancel: record.canCancel ? () => notifier.cancelWithdraw(record.id) : null, ); }, ), ), ); } } // ── 提币记录条目(对齐原型 record-item)──────────────────────────── class _RecordItem extends StatelessWidget { const _RecordItem({ required this.record, this.onCancel, }); final WithdrawRecord record; final VoidCallback? onCancel; String _localizedStatus(AppLocalizations l10n) { switch (record.status) { case '0': return l10n.withdrawStatusReviewing; case '1': return l10n.withdrawStatusReleasing; case '2': return l10n.withdrawStatusFailed; case '3': return l10n.withdrawStatusSuccess; case '4': return l10n.withdrawStatusCancelled; default: return l10n.unknown; } } @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; final isTransfer = record.isTransfer; final baseCoin = record.coin?.baseCoinDisplay.isNotEmpty == true ? record.coin!.baseCoinDisplay : (record.coin?.coinName.isNotEmpty == true ? record.coin!.coinName : 'USDT'); final coinUnit = baseCoin; final l10n = AppLocalizations.of(context)!; final direction = isTransfer ? '$baseCoin ${l10n.internalTransfer}' : '$baseCoin ${l10n.onChainWithdraw}'; final network = isTransfer ? l10n.internalLabel : (record.coin?.networkName ?? ''); // 内部转账用 transferAmount(JSON: amount),链上提币用 amount(JSON: totalAmount) final rawAmount = isTransfer ? record.transferAmount : record.amount; final amountDouble = double.tryParse(rawAmount) ?? 0; final amountStr = formatAmount(amountDouble); Color statusColor; switch (record.status) { case '3': statusColor = AppColors.rise; break; case '2': statusColor = AppColors.fall; break; case '4': statusColor = cs.onSurface.withAlpha(120); break; default: statusColor = AppColors.warning; } return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () => context.push( '/asset/withdraw/detail?isTransfer=$isTransfer', extra: record, ), child: Container( margin: const EdgeInsets.only(bottom: 10), decoration: BoxDecoration( color: isDark ? AppColors.darkBgSecondary : AppColors.lightBg, borderRadius: BorderRadius.circular(12), boxShadow: isDark ? null : [ BoxShadow( color: Colors.black.withAlpha(13), blurRadius: 2, offset: const Offset(0, 1), ) ], ), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ── 上行:方向 + 金额 ────────────────────────────── Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( direction, style: TextStyle( color: cs.onSurface, fontSize: 12, fontWeight: FontWeight.w600, ), ), Text( '-$amountStr $coinUnit', style: TextStyle( color: cs.onSurface, fontSize: 14, fontWeight: FontWeight.w700, ), ), ], ), const SizedBox(height: 6), // ── 下行:时间(左)+ 网络(居中)+ 状态(右)──────────── Row( children: [ Expanded( child: Text( record.createTime, style: TextStyle( color: cs.onSurface.withAlpha(100), fontSize: 10), ), ), if (network.isNotEmpty) Text( network, style: TextStyle( color: cs.onSurface.withAlpha(100), fontSize: 10), ), Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Text( _localizedStatus(l10n), style: TextStyle( color: statusColor, fontSize: 10, fontWeight: FontWeight.w500, ), ), if (onCancel != null) ...[ const SizedBox(width: 10), GestureDetector( onTap: onCancel, child: Text( AppLocalizations.of(context)!.cancel, style: TextStyle( color: AppColors.brand, fontSize: 10, fontWeight: FontWeight.w500, ), ), ), ], ], ), ), ], ), ], ), ), ); } }