import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart'; import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_spacing.dart'; import '../../../providers/asset_provider.dart'; import '../../../data/models/account_models.dart'; /// 划转页面 class TransferPage extends StatefulWidget { const TransferPage({super.key}); @override State createState() => _TransferPageState(); } class _TransferPageState extends State { final _amountController = TextEditingController(); final _focusNode = FocusNode(); int _direction = 1; // 1: 资金→交易, 2: 交易→资金 bool _isLoading = false; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().refreshAll(force: true); }); } @override void dispose() { _amountController.dispose(); _focusNode.dispose(); super.dispose(); } /// 获取资金账户余额 String get _fundBalance { final provider = context.read(); return provider.fundAccount?.balance ?? provider.overview?.fundBalance ?? '0.00'; } /// 获取交易账户 USDT 余额 String get _tradeUsdtBalance { final provider = context.read(); final usdtHolding = provider.tradeAccounts.firstWhere( (t) => t.coinCode.toUpperCase() == 'USDT', orElse: () => AccountTrade( id: 0, userId: 0, coinCode: 'USDT', quantity: '0', avgPrice: '1', totalCost: '0', currentValue: '0', profit: '0', profitRate: 0, ), ); return usdtHolding.quantity; } /// 获取当前可用余额(根据方向) String get _availableBalance { return _direction == 1 ? _fundBalance : _tradeUsdtBalance; } /// 从账户名 String get _fromLabel => _direction == 1 ? '资金账户' : '交易账户'; String get _toLabel => _direction == 1 ? '交易账户' : '资金账户'; String get _fromBalance => _direction == 1 ? _fundBalance : _tradeUsdtBalance; String get _toBalance => _direction == 1 ? _tradeUsdtBalance : _fundBalance; /// 执行划转 Future _doTransfer() async { final amount = _amountController.text; final available = double.tryParse(_availableBalance) ?? 0; final transferAmount = double.tryParse(amount) ?? 0; if (transferAmount <= 0) { _showSnackBar('请输入有效的划转金额'); return; } if (transferAmount > available) { _showSnackBar('余额不足'); return; } setState(() => _isLoading = true); try { final response = await context.read().transfer( direction: _direction, amount: amount, ); if (mounted) { if (response.success) { _amountController.clear(); _showSnackBar('划转成功'); Navigator.of(context).pop(true); } else { _showSnackBar(response.message ?? '划转失败'); } } } finally { if (mounted) { setState(() => _isLoading = false); } } } void _showSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(message)), ); } /// 设置快捷百分比金额 void _setQuickAmount(double percent) { final available = double.tryParse(_availableBalance) ?? 0; final amount = available * percent; _amountController.text = amount.toStringAsFixed(8).replaceAll(RegExp(r'\.?0+$'), ''); } /// 切换方向 void _toggleDirection() { setState(() { _direction = _direction == 1 ? 2 : 1; }); } @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; // Theme-aware colors matching .pen design tokens final bgSecondary = isDark ? const Color(0xFF0B1120) : const Color(0xFFF8FAFC); final surfaceCard = isDark ? const Color(0xFF0F172A) : const Color(0xFFFFFFFF); final bgTertiary = isDark ? const Color(0xFF1E293B) : const Color(0xFFF1F5F9); final borderDefault = isDark ? const Color(0xFF334155) : const Color(0xFFE2E8F0); final textPrimary = isDark ? const Color(0xFFF8FAFC) : const Color(0xFF0F172A); final textSecondary = isDark ? const Color(0xFF94A3B8) : const Color(0xFF475569); final textMuted = isDark ? const Color(0xFF64748B) : const Color(0xFF94A3B8); final textInverse = isDark ? const Color(0xFF0F172A) : const Color(0xFFFFFFFF); final accentPrimary = isDark ? const Color(0xFFD4AF37) : const Color(0xFF1F2937); final goldAccent = isDark ? const Color(0xFFD4AF37) : const Color(0xFFF59E0B); final profitGreen = isDark ? const Color(0xFF4ADE80) : const Color(0xFF16A34A); final profitGreenBg = isDark ? const Color(0xFF052E16) : const Color(0xFFF0FDF4); return Scaffold( backgroundColor: bgSecondary, appBar: AppBar( backgroundColor: isDark ? const Color(0xFF0F172A) : const Color(0xFFFFFFFF), elevation: 0, scrolledUnderElevation: 0, leading: IconButton( icon: Icon(LucideIcons.arrowLeft, color: textPrimary, size: 20), onPressed: () => Navigator.of(context).pop(), ), title: Text( '账户划转', style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.w600, color: textPrimary, ), ), centerTitle: true, ), body: Consumer( builder: (context, provider, _) { return SingleChildScrollView( padding: const EdgeInsets.fromLTRB(16, 16, 16, 32), child: Column( children: [ // --- Transfer Direction Card --- _buildTransferDirectionCard( colorScheme: colorScheme, isDark: isDark, surfaceCard: surfaceCard, borderDefault: borderDefault, textPrimary: textPrimary, textSecondary: textSecondary, textMuted: textMuted, textInverse: textInverse, accentPrimary: accentPrimary, ), const SizedBox(height: 24), // --- Amount Section --- _buildAmountSection( isDark: isDark, bgTertiary: bgTertiary, textPrimary: textPrimary, textSecondary: textSecondary, textMuted: textMuted, goldAccent: goldAccent, ), const SizedBox(height: 24), // --- Tips Card --- _buildTipsCard( profitGreen: profitGreen, profitGreenBg: profitGreenBg, ), const SizedBox(height: 24), // --- Confirm Button --- _buildConfirmButton( accentPrimary: accentPrimary, textInverse: textInverse, ), ], ), ); }, ), ); } /// Transfer direction card with source, swap, destination Widget _buildTransferDirectionCard({ required ColorScheme colorScheme, required bool isDark, required Color surfaceCard, required Color borderDefault, required Color textPrimary, required Color textSecondary, required Color textMuted, required Color textInverse, required Color accentPrimary, }) { return Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: surfaceCard, borderRadius: BorderRadius.circular(AppRadius.xl), border: Border.all(color: borderDefault.withOpacity(0.6)), ), child: Column( children: [ // Source account AnimatedSwitcher( duration: const Duration(milliseconds: 300), switchInCurve: Curves.easeInOut, switchOutCurve: Curves.easeInOut, transitionBuilder: (widget, animation) { return SlideTransition( position: Tween( begin: const Offset(0, -1), end: Offset.zero, ).animate(animation), child: FadeTransition(opacity: animation, child: widget), ); }, child: _buildAccountRow( key: ValueKey('src-$_direction'), label: '从', accountName: _fromLabel, balance: _fromBalance, isDark: isDark, textMuted: textMuted, textPrimary: textPrimary, textSecondary: textSecondary, ), ), // Swap button GestureDetector( onTap: _toggleDirection, child: Container( width: 36, height: 36, margin: const EdgeInsets.symmetric(vertical: 16), decoration: BoxDecoration( color: accentPrimary, shape: BoxShape.circle, ), child: Center( child: Icon( LucideIcons.arrowUpDown, size: 18, color: textInverse, ), ), ), ), // Destination account AnimatedSwitcher( duration: const Duration(milliseconds: 300), switchInCurve: Curves.easeInOut, switchOutCurve: Curves.easeInOut, transitionBuilder: (widget, animation) { return SlideTransition( position: Tween( begin: const Offset(0, 1), end: Offset.zero, ).animate(animation), child: FadeTransition(opacity: animation, child: widget), ); }, child: _buildAccountRow( key: ValueKey('dst-$_direction'), label: '到', accountName: _toLabel, balance: _toBalance, isDark: isDark, textMuted: textMuted, textPrimary: textPrimary, textSecondary: textSecondary, ), ), ], ), ); } /// Single account row inside the direction card Widget _buildAccountRow({ Key? key, required String label, required String accountName, required String balance, required bool isDark, required Color textMuted, required Color textPrimary, required Color textSecondary, }) { return Container( key: key, width: double.infinity, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Label row Text( label, style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.normal, color: textMuted, ), ), const SizedBox(height: 8), // Account name + balance row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // Account name with icon Row( children: [ Icon( label == '从' ? LucideIcons.wallet : LucideIcons.repeat, size: 18, color: textSecondary, ), const SizedBox(width: 10), Text( accountName, style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.w600, color: textPrimary, ), ), ], ), // Balance Text( '\u00A5 ${_formatBalance(balance)}', style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.w600, color: textPrimary, ), ), ], ), ], ), ); } /// Format balance for display String _formatBalance(String balance) { final val = double.tryParse(balance); if (val == null) return '0.00'; return val.toStringAsFixed(2); } /// Amount input section Widget _buildAmountSection({ required bool isDark, required Color bgTertiary, required Color textPrimary, required Color textSecondary, required Color textMuted, required Color goldAccent, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Label row: "划转金额" + "全部划转" Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '划转金额', style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.w500, color: textSecondary, ), ), GestureDetector( onTap: () => _setQuickAmount(1.0), child: Text( '全部划转', style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.w600, color: goldAccent, ), ), ), ], ), const SizedBox(height: 12), // Amount input field GestureDetector( onTap: () => _focusNode.requestFocus(), child: Container( width: double.infinity, height: 56, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( color: bgTertiary, borderRadius: BorderRadius.circular(AppRadius.lg), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // Input Expanded( child: TextField( controller: _amountController, focusNode: _focusNode, keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,8}')), ], style: GoogleFonts.inter( fontSize: 28, fontWeight: FontWeight.w700, color: textPrimary, ), decoration: InputDecoration( hintText: '0.00', hintStyle: GoogleFonts.inter( fontSize: 28, fontWeight: FontWeight.w700, color: textMuted, ), border: InputBorder.none, contentPadding: EdgeInsets.zero, isDense: true, ), ), ), // Suffix Padding( padding: const EdgeInsets.only(left: 8), child: Text( 'USDT', style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.normal, color: textMuted, ), ), ), ], ), ), ), const SizedBox(height: 12), // Percent buttons Row( children: [ _buildPercentButton('25%', 0.25, isDark, bgTertiary, textSecondary), const SizedBox(width: 8), _buildPercentButton('50%', 0.50, isDark, bgTertiary, textSecondary), const SizedBox(width: 8), _buildPercentButton('75%', 0.75, isDark, bgTertiary, textSecondary), const SizedBox(width: 8), _buildPercentButton('100%', 1.0, isDark, bgTertiary, textSecondary), ], ), ], ); } /// Percent quick button Widget _buildPercentButton(String label, double percent, bool isDark, Color bgTertiary, Color textSecondary) { return Expanded( child: GestureDetector( onTap: () => _setQuickAmount(percent), child: Container( height: 36, decoration: BoxDecoration( color: bgTertiary, borderRadius: BorderRadius.circular(AppRadius.sm), ), child: Center( child: Text( label, style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w500, color: textSecondary, ), ), ), ), ), ); } /// Tips card with green background Widget _buildTipsCard({ required Color profitGreen, required Color profitGreenBg, }) { return Container( width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: profitGreenBg, borderRadius: BorderRadius.circular(AppRadius.lg), ), child: Row( children: [ Icon( LucideIcons.info, size: 16, color: profitGreen, ), const SizedBox(width: 8), Expanded( child: Text( '划转即时到账,无需手续费', style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.normal, color: profitGreen, ), ), ), ], ), ); } /// Confirm button Widget _buildConfirmButton({ required Color accentPrimary, required Color textInverse, }) { return SizedBox( width: double.infinity, height: 52, child: GestureDetector( onTap: _isLoading ? null : _doTransfer, child: Container( decoration: BoxDecoration( color: accentPrimary, borderRadius: BorderRadius.circular(AppRadius.lg), ), child: Center( child: _isLoading ? SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(textInverse), ), ) : Text( '确认划转', style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.w700, color: textInverse, ), ), ), ), ), ); } }