import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart'; import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_spacing.dart'; import '../../../providers/asset_provider.dart'; import '../../../data/models/account_models.dart'; import '../../components/material_input.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(); _amountController.addListener(() => setState(() {})); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().refreshAll(force: true); }); } @override void dispose() { _amountController.dispose(); _focusNode.dispose(); super.dispose(); } // ============================================ // 数据访问 // ============================================ String get _fundBalance { try { final provider = context.read(); final balance = provider.fundAccount?.balance ?? provider.overview?.fundBalance ?? '0.00'; return _formatBalance(balance); } catch (e) { return '0.00'; } } String get _tradeUsdtBalance { try { final provider = context.read(); if (provider.tradeAccounts.isEmpty) return '0.00'; 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 _formatBalance(usdtHolding.quantity); } catch (e) { return '0.00'; } } String get _availableBalance => _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('劃轉成功'); await Future.delayed(const Duration(milliseconds: 500)); if (mounted) 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), behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), ); } void _setQuickAmount(double percent) { final available = double.tryParse(_availableBalance) ?? 0; final amount = available * percent; // 向下截斷到2位小數,避免四捨五入超出餘額 _amountController.text = ((amount * 100).truncateToDouble() / 100).toStringAsFixed(2); // Trigger haptic feedback HapticFeedback.selectionClick(); } void _toggleDirection() { HapticFeedback.mediumImpact(); setState(() => _direction = _direction == 1 ? 2 : 1); } // ============================================ // 构建 UI // ============================================ @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Scaffold( backgroundColor: colorScheme.surface, appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, scrolledUnderElevation: 0, leading: IconButton( icon: Icon(LucideIcons.arrowLeft, color: colorScheme.onSurface, size: 20), onPressed: () => Navigator.of(context).pop(), ), title: Text( '賬戶劃轉', style: AppTextStyles.headlineLarge(context).copyWith( fontWeight: FontWeight.w600, ), ), centerTitle: true, ), body: Consumer( builder: (context, provider, _) { return SingleChildScrollView( padding: const EdgeInsets.fromLTRB( AppSpacing.md, AppSpacing.xs, AppSpacing.md, AppSpacing.xl), child: Column( children: [ _buildTransferCard(colorScheme), const SizedBox(height: AppSpacing.md), _buildAmountSection(colorScheme), const SizedBox(height: AppSpacing.md), _buildTips(colorScheme), const SizedBox(height: AppSpacing.xl), _buildConfirmButton(colorScheme), const SizedBox(height: AppSpacing.lg), ], ), ); }, ), ); } // ============================================ // 划转方向卡片 // ============================================ Widget _buildTransferCard(ColorScheme colorScheme) { return Container( width: double.infinity, decoration: BoxDecoration( color: colorScheme.surface, borderRadius: BorderRadius.circular(20), border: Border.all( color: colorScheme.outlineVariant.withValues(alpha: 0.5), width: 1, ), ), child: Stack( clipBehavior: Clip.none, children: [ Column( children: [ // From Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Text( '从', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), const SizedBox(width: 8), Text( _fromLabel, style: AppTextStyles.bodyLarge(context).copyWith( fontWeight: FontWeight.w500, ), ), ], ), Text( _fromBalance, style: AppTextStyles.bodyLarge(context).copyWith( fontWeight: FontWeight.w600, ), ), ], ), ), Divider( height: 1, thickness: 1, color: colorScheme.outlineVariant.withValues(alpha: 0.5), ), // To Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Text( '到', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), const SizedBox(width: 8), Text( _toLabel, style: AppTextStyles.bodyLarge(context).copyWith( fontWeight: FontWeight.w500, ), ), ], ), Text( _toBalance, style: AppTextStyles.bodyLarge(context).copyWith( fontWeight: FontWeight.w600, ), ), ], ), ), ], ), // 交换按钮 - 右側居中分割線 Positioned( right: 12, top: 20, bottom: 20, child: Center( child: GestureDetector( onTap: _toggleDirection, child: Container( width: 28, height: 28, decoration: BoxDecoration( color: colorScheme.surface, shape: BoxShape.circle, border: Border.all( color: colorScheme.outlineVariant, width: 1, ), ), child: Icon( LucideIcons.repeat2, size: 13, color: colorScheme.onSurfaceVariant, ), ), ), ), ), ], ), ); } // ============================================ // 金额输入区域 // ============================================ Widget _buildAmountSection(ColorScheme colorScheme) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 标题行 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '劃轉金額', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500, ), ), GestureDetector( onTap: () => _setQuickAmount(1.0), child: Text( '全部', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.secondary, fontWeight: FontWeight.w500, ), ), ), ], ), const SizedBox(height: 12), // 金额输入框 MaterialInput( controller: _amountController, focusNode: _focusNode, hintText: '0.00', keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,8}')), ], onChanged: (_) => setState(() {}), suffixIcon: Padding( padding: const EdgeInsets.only(right: AppSpacing.md), child: Text( 'USDT', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500, ), ), ), ), const SizedBox(height: 10), // 可用余额 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '可用餘額', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), Text( '$_availableBalance USDT', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 12), // 百分比按钮 Row( children: [ _buildPercentButton('25%', 0.25, colorScheme), const SizedBox(width: 8), _buildPercentButton('50%', 0.50, colorScheme), const SizedBox(width: 8), _buildPercentButton('75%', 0.75, colorScheme), const SizedBox(width: 8), _buildPercentButton('100%', 1.0, colorScheme), ], ), ], ); } Widget _buildPercentButton( String label, double percent, ColorScheme colorScheme) { return Expanded( child: GestureDetector( onTap: () => _setQuickAmount(percent), child: Container( height: 34, decoration: BoxDecoration( color: colorScheme.surfaceContainerHighest.withValues(alpha: 0.5), borderRadius: BorderRadius.circular(8), ), child: Center( child: Text( label, style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500, ), ), ), ), ), ); } // ============================================ // 提示文字 // ============================================ Widget _buildTips(ColorScheme colorScheme) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: [ Icon(LucideIcons.info, size: 13, color: colorScheme.onSurfaceVariant), const SizedBox(width: 6), Text( '劃轉即時到賬,無需手續費', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), ), ], ), ); } // ============================================ // 确认按钮 // ============================================ Widget _buildConfirmButton(ColorScheme colorScheme) { final hasAmount = _amountController.text.isNotEmpty && double.tryParse(_amountController.text) != null && double.parse(_amountController.text) > 0; return SizedBox( width: double.infinity, height: 48, child: ElevatedButton( onPressed: _isLoading ? null : _doTransfer, style: ElevatedButton.styleFrom( backgroundColor: hasAmount ? colorScheme.onSurface : colorScheme.surfaceContainerHighest, foregroundColor: hasAmount ? colorScheme.surface : colorScheme.onSurfaceVariant, disabledBackgroundColor: colorScheme.surfaceContainerHighest, disabledForegroundColor: colorScheme.onSurfaceVariant, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), ), ), child: _isLoading ? SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( colorScheme.onSurfaceVariant, ), ), ) : Text( '確認劃轉', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, ), ), ), ); } // ============================================ // Helpers // ============================================ String _formatBalance(String balance) { final val = double.tryParse(balance); if (val == null) return '0.00'; return val.toStringAsFixed(2); } }