import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:provider/provider.dart'; import 'package:google_fonts/google_fonts.dart'; import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_spacing.dart'; import '../../../data/models/coin.dart'; import '../../../providers/market_provider.dart'; import '../../../providers/asset_provider.dart'; import '../../shared/ui_constants.dart'; import '../../components/glass_panel.dart'; import '../../components/neon_glow.dart'; /// 交易页面 - Material Design 3 风格 class TradePage extends StatefulWidget { const TradePage({super.key}); @override State createState() => _TradePageState(); } class _TradePageState extends State with AutomaticKeepAliveClientMixin { int _tradeType = 0; // 0=买入, 1=卖出 Coin? _selectedCoin; final _formKey = GlobalKey(); final _priceController = TextEditingController(); final _quantityController = TextEditingController(); @override bool get wantKeepAlive => true; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) => _loadData()); } void _loadData() { context.read().loadCoins(); } @override void dispose() { _priceController.dispose(); _quantityController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { super.build(context); return Scaffold( backgroundColor: AppColorScheme.darkBackground, body: Consumer2( builder: (context, market, asset, _) { return SingleChildScrollView( padding: AppSpacing.pagePadding, child: ShadForm( key: _formKey, child: Column( children: [ _CoinSelector( selectedCoin: _selectedCoin, coins: market.allCoins, onCoinLoaded: (coin) { _selectedCoin = coin; _priceController.text = coin.formattedPrice; }, ), SizedBox(height: AppSpacing.md), if (_selectedCoin != null) _PriceCard(coin: _selectedCoin!), SizedBox(height: AppSpacing.md), _TradeForm( tradeType: _tradeType, selectedCoin: _selectedCoin, priceController: _priceController, quantityController: _quantityController, tradeBalance: asset.overview?.tradeBalance, onTradeTypeChanged: (type) => setState(() => _tradeType = type), ), SizedBox(height: AppSpacing.lg), _TradeButton( isBuy: _tradeType == 0, coinCode: _selectedCoin?.code, onPressed: () { if (_formKey.currentState!.saveAndValidate()) { _executeTrade(); } }, ), ], ), ), ); }, ), ); } void _executeTrade() { final price = _priceController.text; final quantity = _quantityController.text; final isBuy = _tradeType == 0; showShadDialog( context: context, builder: (ctx) => ShadDialog.alert( title: Text(isBuy ? '确认买入' : '确认卖出'), description: Text('${isBuy ? '买入' : '卖出'} $quantity ${_selectedCoin?.code ?? ''} @ $price USDT'), actions: [ ShadButton.outline(child: const Text('取消'), onPressed: () => Navigator.of(ctx).pop()), ShadButton( child: const Text('确认'), onPressed: () { Navigator.of(ctx).pop(); _showTradeResult(); }, ), ], ), ); } void _showTradeResult() { final isBuy = _tradeType == 0; showShadDialog( context: context, builder: (ctx) => ShadDialog.alert( title: Row( children: [ NeonIcon( icon: Icons.check_circle, color: AppColorScheme.darkPrimary, size: 24, ), SizedBox(width: AppSpacing.sm), const Text('交易成功'), ], ), description: Text('已${isBuy ? '买入' : '卖出'} ${_quantityController.text} ${_selectedCoin?.code ?? ''}'), actions: [ ShadButton( child: const Text('确定'), onPressed: () { Navigator.of(ctx).pop(); _quantityController.clear(); }, ), ], ), ); } } /// 币种选择器 - Glass Panel 风格 class _CoinSelector extends StatelessWidget { final Coin? selectedCoin; final List coins; final ValueChanged onCoinLoaded; const _CoinSelector({ required this.selectedCoin, required this.coins, required this.onCoinLoaded, }); @override Widget build(BuildContext context) { // 自动选择第一个币种 if (selectedCoin == null && coins.isNotEmpty) { WidgetsBinding.instance.addPostFrameCallback((_) => onCoinLoaded(coins.first)); } return GlassCard( showNeonGlow: false, child: Row( children: [ _CoinAvatar(icon: selectedCoin?.displayIcon), SizedBox(width: AppSpacing.sm + AppSpacing.xs), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( selectedCoin != null ? '${selectedCoin!.code}/USDT' : '选择币种', style: GoogleFonts.spaceGrotesk( fontSize: 18, fontWeight: FontWeight.bold, color: AppColorScheme.darkOnSurface, ), ), SizedBox(height: AppSpacing.xs), Text( selectedCoin?.name ?? '点击选择交易对', style: TextStyle( fontSize: 12, color: AppColorScheme.darkOnSurfaceVariant, ), ), ], ), ), Icon( LucideIcons.chevronRight, color: AppColorScheme.darkOnSurfaceVariant, ), ], ), ); } } /// 币种头像 - 带霓虹光效 class _CoinAvatar extends StatelessWidget { final String? icon; const _CoinAvatar({this.icon}); @override Widget build(BuildContext context) { return Container( width: 44, height: 44, decoration: BoxDecoration( color: AppColorScheme.darkPrimary.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(AppRadius.md), border: Border.all( color: AppColorScheme.darkPrimary.withValues(alpha: 0.2), ), ), child: Center( child: Text( icon ?? '?', style: TextStyle( fontSize: 20, color: AppColorScheme.darkPrimary, fontWeight: FontWeight.bold, ), ), ), ); } } /// 价格卡片 - Glass Panel 风格 class _PriceCard extends StatelessWidget { final Coin coin; const _PriceCard({required this.coin}); @override Widget build(BuildContext context) { final color = coin.isUp ? AppColorScheme.up : AppColorScheme.down; final bgColor = coin.isUp ? AppColorScheme.darkTertiary.withValues(alpha: 0.1) : AppColorScheme.darkError.withValues(alpha: 0.1); return GlassCard( showNeonGlow: false, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '最新价', style: TextStyle( fontSize: 12, color: AppColorScheme.darkOnSurfaceVariant, ), ), SizedBox(height: AppSpacing.xs), Text( '\$${coin.formattedPrice}', style: GoogleFonts.spaceGrotesk( fontSize: 28, fontWeight: FontWeight.bold, color: AppColorScheme.darkOnSurface, ), ), ], ), Container( padding: EdgeInsets.symmetric( horizontal: AppSpacing.md, vertical: AppSpacing.sm, ), decoration: BoxDecoration( color: bgColor, borderRadius: BorderRadius.circular(AppRadius.md), border: Border.all( color: color.withValues(alpha: 0.2), ), ), child: Text( coin.formattedChange, style: TextStyle( fontSize: 16, color: color, fontWeight: FontWeight.w700, ), ), ), ], ), ); } } /// 交易表单 - Glass Panel 风格 class _TradeForm extends StatelessWidget { final int tradeType; final Coin? selectedCoin; final TextEditingController priceController; final TextEditingController quantityController; final String? tradeBalance; final ValueChanged onTradeTypeChanged; const _TradeForm({ required this.tradeType, required this.selectedCoin, required this.priceController, required this.quantityController, required this.tradeBalance, required this.onTradeTypeChanged, }); @override Widget build(BuildContext context) { return GlassPanel( padding: EdgeInsets.all(AppSpacing.lg), child: Column( children: [ // 买入/卖出切换 _TradeTypeSelector( tradeType: tradeType, onChanged: onTradeTypeChanged, ), SizedBox(height: AppSpacing.lg), // 价格输入 _buildInputField( label: '价格(USDT)', controller: priceController, placeholder: '输入价格', suffix: 'USDT', ), SizedBox(height: AppSpacing.md), // 数量输入 _buildInputField( label: '数量', controller: quantityController, placeholder: '输入数量', suffix: selectedCoin?.code ?? '', ), SizedBox(height: AppSpacing.lg), // 信息行 _InfoRow(label: '交易金额', value: '${_calculateAmount()} USDT'), SizedBox(height: AppSpacing.sm), _InfoRow(label: '可用', value: '${tradeBalance ?? '0.00'} USDT'), ], ), ); } Widget _buildInputField({ required String label, required TextEditingController controller, required String placeholder, required String suffix, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle( fontSize: 10, fontWeight: FontWeight.w700, letterSpacing: 0.2, color: AppColorScheme.darkOnSurfaceVariant, ), ), SizedBox(height: AppSpacing.xs), Container( decoration: BoxDecoration( color: AppColorScheme.darkSurfaceLowest, borderRadius: BorderRadius.circular(AppRadius.xl), border: Border.all( color: AppColorScheme.darkOutlineVariant.withValues(alpha: 0.3), ), ), child: TextField( controller: controller, keyboardType: const TextInputType.numberWithOptions(decimal: true), style: GoogleFonts.spaceGrotesk( fontSize: 20, fontWeight: FontWeight.bold, color: AppColorScheme.darkOnSurface, ), decoration: InputDecoration( hintText: placeholder, hintStyle: TextStyle( color: AppColorScheme.darkOutlineVariant.withValues(alpha: 0.5), ), border: InputBorder.none, contentPadding: EdgeInsets.symmetric( horizontal: AppSpacing.md, vertical: AppSpacing.md, ), suffixIcon: Padding( padding: EdgeInsets.only(right: AppSpacing.sm), child: Text( suffix, style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: AppColorScheme.darkOnSurfaceVariant, ), ), ), suffixIconConstraints: const BoxConstraints(minWidth: 50), ), ), ), ], ); } String _calculateAmount() { final price = double.tryParse(priceController.text) ?? 0; final quantity = double.tryParse(quantityController.text) ?? 0; return (price * quantity).toStringAsFixed(2); } } /// 交易类型选择器 - Material Design 3 风格 class _TradeTypeSelector extends StatelessWidget { final int tradeType; final ValueChanged onChanged; const _TradeTypeSelector({required this.tradeType, required this.onChanged}); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(AppSpacing.xs), decoration: BoxDecoration( color: AppColorScheme.darkSurfaceLowest, borderRadius: BorderRadius.circular(AppRadius.xl), ), child: Row( children: [ Expanded( child: _TypeButton( label: 'Buy', isSelected: tradeType == 0, color: AppColorScheme.up, onTap: () => onChanged(0), ), ), SizedBox(width: AppSpacing.sm), Expanded( child: _TypeButton( label: 'Sell', isSelected: tradeType == 1, color: AppColorScheme.down, onTap: () => onChanged(1), ), ), ], ), ); } } /// 类型按钮 class _TypeButton extends StatelessWidget { final String label; final bool isSelected; final Color color; final VoidCallback onTap; const _TypeButton({ required this.label, required this.isSelected, required this.color, required this.onTap, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: EdgeInsets.symmetric(vertical: AppSpacing.sm + AppSpacing.xs), decoration: BoxDecoration( color: isSelected ? color.withValues(alpha: 0.15) : Colors.transparent, borderRadius: BorderRadius.circular(AppRadius.md), border: isSelected ? null : Border.all(color: color.withValues(alpha: 0.3)), ), child: Center( child: Text( label, style: TextStyle( color: isSelected ? color : color.withValues(alpha: 0.7), fontWeight: FontWeight.w700, fontSize: 14, letterSpacing: 0.5, ), ), ), ), ); } } /// 信息行 class _InfoRow extends StatelessWidget { final String label; final String value; const _InfoRow({required this.label, required this.value}); @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: TextStyle( fontSize: 14, color: AppColorScheme.darkOnSurfaceVariant, ), ), Text( value, style: GoogleFonts.spaceGrotesk( fontSize: 14, fontWeight: FontWeight.w600, color: AppColorScheme.darkOnSurface, ), ), ], ); } } /// 交易按钮 - 带霓虹光效 class _TradeButton extends StatelessWidget { final bool isBuy; final String? coinCode; final VoidCallback onPressed; const _TradeButton({ required this.isBuy, required this.coinCode, required this.onPressed, }); @override Widget build(BuildContext context) { return NeonButton( text: '${isBuy ? '买入' : '卖出'} ${coinCode ?? ''}', type: isBuy ? NeonButtonType.tertiary : NeonButtonType.error, icon: isBuy ? Icons.arrow_downward : Icons.arrow_upward, onPressed: onPressed, width: double.infinity, showGlow: true, ); } }