import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:provider/provider.dart'; import '../../../data/models/coin.dart'; import '../../../providers/market_provider.dart'; import '../../../providers/asset_provider.dart'; /// 交易页面 - 使用 shadcn_ui 现代化设计 class TradePage extends StatefulWidget { const TradePage({super.key}); @override State createState() => _TradePageState(); } class _TradePageState extends State with AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; int _tradeType = 0; // 0=买入, 1=卖出 Coin? _selectedCoin; final _formKey = GlobalKey(); final _priceController = TextEditingController(); final _quantityController = TextEditingController(); // 颜色常量 static const upColor = Color(0xFF00C853); static const downColor = Color(0xFFFF5252); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { _loadData(); }); } void _loadData() { context.read().loadCoins(); context.read().loadOverview(); } @override void dispose() { _priceController.dispose(); _quantityController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { super.build(context); final theme = ShadTheme.of(context); return Scaffold( backgroundColor: theme.colorScheme.background, body: Consumer2( builder: (context, market, asset, _) { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: ShadForm( key: _formKey, child: Column( children: [ _buildCoinSelector(market), const SizedBox(height: 16), _buildPriceCard(), const SizedBox(height: 16), _buildTradeForm(asset), const SizedBox(height: 16), _buildTradeButton(), ], ), ), ); }, ), ); } Widget _buildCoinSelector(MarketProvider market) { final theme = ShadTheme.of(context); final coins = market.allCoins; if (_selectedCoin == null && coins.isNotEmpty) { _selectedCoin = coins.first; _priceController.text = _selectedCoin!.formattedPrice; } return ShadCard( padding: const EdgeInsets.all(16), child: Row( children: [ CircleAvatar( radius: 22, backgroundColor: theme.colorScheme.primary.withValues(alpha: 0.1), child: Text( _selectedCoin?.displayIcon ?? '?', style: TextStyle( fontSize: 20, color: theme.colorScheme.primary, ), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _selectedCoin != null ? '${_selectedCoin!.code}/USDT' : '选择币种', style: theme.textTheme.large.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( _selectedCoin != null ? _selectedCoin!.name : '点击选择交易对', style: theme.textTheme.muted, ), ], ), ), Icon( LucideIcons.chevronRight, color: theme.colorScheme.mutedForeground, ), ], ), ); } Widget _buildPriceCard() { final theme = ShadTheme.of(context); if (_selectedCoin == null) { return const SizedBox.shrink(); } final coin = _selectedCoin!; return ShadCard( padding: const EdgeInsets.all(16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '最新价', style: theme.textTheme.muted, ), const SizedBox(height: 4), Text( '\$${coin.formattedPrice}', style: theme.textTheme.h2.copyWith( fontWeight: FontWeight.bold, ), ), ], ), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: coin.isUp ? upColor.withValues(alpha: 0.2) : downColor.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(8), ), child: Text( coin.formattedChange, style: TextStyle( fontSize: 16, color: coin.isUp ? upColor : downColor, fontWeight: FontWeight.w600, ), ), ), ], ), ); } Widget _buildTradeForm(AssetProvider asset) { final theme = ShadTheme.of(context); return ShadCard( padding: const EdgeInsets.all(16), child: Column( children: [ // 买入/卖出切换 Row( children: [ Expanded( child: GestureDetector( onTap: () => setState(() => _tradeType = 0), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _tradeType == 0 ? upColor : Colors.transparent, borderRadius: BorderRadius.circular(8), border: _tradeType != 0 ? Border.all(color: upColor) : null, ), child: Center( child: Text( '买入', style: TextStyle( color: _tradeType == 0 ? Colors.white : upColor, fontWeight: FontWeight.w600, ), ), ), ), ), ), const SizedBox(width: 16), Expanded( child: GestureDetector( onTap: () => setState(() => _tradeType = 1), child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _tradeType == 1 ? downColor : Colors.transparent, borderRadius: BorderRadius.circular(8), border: _tradeType != 1 ? Border.all(color: downColor) : null, ), child: Center( child: Text( '卖出', style: TextStyle( color: _tradeType == 1 ? Colors.white : downColor, fontWeight: FontWeight.w600, ), ), ), ), ), ), ], ), const SizedBox(height: 20), // 价格输入 ShadInputFormField( id: 'price', label: const Text('价格(USDT)'), controller: _priceController, keyboardType: const TextInputType.numberWithOptions(decimal: true), placeholder: const Text('输入价格'), trailing: const Padding( padding: EdgeInsets.only(right: 8), child: Text('USDT'), ), validator: (value) { if (value == null || value.isEmpty) { return '请输入价格'; } final price = double.tryParse(value); if (price == null || price <= 0) { return '请输入有效价格'; } return null; }, ), const SizedBox(height: 12), // 数量输入 ShadInputFormField( id: 'quantity', label: const Text('数量'), controller: _quantityController, keyboardType: const TextInputType.numberWithOptions(decimal: true), placeholder: const Text('输入数量'), trailing: Padding( padding: const EdgeInsets.only(right: 8), child: Text(_selectedCoin?.code ?? ''), ), validator: (value) { if (value == null || value.isEmpty) { return '请输入数量'; } final quantity = double.tryParse(value); if (quantity == null || quantity <= 0) { return '请输入有效数量'; } return null; }, ), const SizedBox(height: 16), // 交易金额 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '交易金额', style: theme.textTheme.muted, ), Text( '${_calculateAmount()} USDT', style: theme.textTheme.small.copyWith( fontWeight: FontWeight.w600, ), ), ], ), const SizedBox(height: 8), // 可用余额 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '可用', style: theme.textTheme.muted, ), Text( '${asset.overview?.tradeBalance ?? '0.00'} USDT', style: theme.textTheme.muted, ), ], ), ], ), ); } String _calculateAmount() { final price = double.tryParse(_priceController.text) ?? 0; final quantity = double.tryParse(_quantityController.text) ?? 0; return (price * quantity).toStringAsFixed(2); } Widget _buildTradeButton() { final isBuy = _tradeType == 0; final color = isBuy ? upColor : downColor; return SizedBox( width: double.infinity, height: 48, child: ShadButton( backgroundColor: color, onPressed: () { if (_formKey.currentState!.saveAndValidate()) { _executeTrade(); } }, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( isBuy ? LucideIcons.arrowDownToLine : LucideIcons.arrowUpFromLine, size: 18, color: Colors.white, ), const SizedBox(width: 8), Text( '${isBuy ? '买入' : '卖出'} ${_selectedCoin?.code ?? ''}', style: const TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600, ), ), ], ), ), ); } void _executeTrade() { final price = _priceController.text; final quantity = _quantityController.text; showShadDialog( context: context, builder: (context) => ShadDialog.alert( title: Text(_tradeType == 0 ? '确认买入' : '确认卖出'), description: Text( '${_tradeType == 0 ? '买入' : '卖出'} $quantity ${_selectedCoin?.code ?? ''} @ $price USDT', ), actions: [ ShadButton.outline( child: const Text('取消'), onPressed: () => Navigator.of(context).pop(), ), ShadButton( child: const Text('确认'), onPressed: () { Navigator.of(context).pop(); _showTradeResult(); }, ), ], ), ); } void _showTradeResult() { final theme = ShadTheme.of(context); showShadDialog( context: context, builder: (context) => ShadDialog.alert( title: Row( children: [ Icon( LucideIcons.circleCheck, color: theme.colorScheme.primary, size: 24, ), const SizedBox(width: 8), const Text('交易成功'), ], ), description: Text( '已${_tradeType == 0 ? '买入' : '卖出'} ${_quantityController.text} ${_selectedCoin?.code ?? ''}', ), actions: [ ShadButton( child: const Text('确定'), onPressed: () { Navigator.of(context).pop(); _quantityController.clear(); }, ), ], ), ); } }