From 9760f7a8a122f30081eab27fa3f5b22c04954298 Mon Sep 17 00:00:00 2001 From: sion123 <450702724@qq.com> Date: Wed, 8 Apr 2026 01:58:53 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E6=96=B0=E5=A2=9E=E7=B2=BE?= =?UTF-8?q?=E9=81=B8=E5=8D=A1=E7=89=87=E6=BC=B8=E8=AE=8A=E8=89=B2=E4=B8=A6?= =?UTF-8?q?=E5=84=AA=E5=8C=96=E5=B8=82=E5=A0=B4=E9=A0=81=E9=9D=A2=E8=A8=AD?= =?UTF-8?q?=E8=A8=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/core/theme/app_color_scheme.dart | 24 ++ .../lib/ui/pages/asset/deposit_page.dart | 46 +-- .../lib/ui/pages/asset/transfer_page.dart | 22 +- .../lib/ui/pages/asset/withdraw_page.dart | 42 +-- .../lib/ui/pages/market/market_page.dart | 332 +++++++++++------- 5 files changed, 289 insertions(+), 177 deletions(-) diff --git a/flutter_monisuo/lib/core/theme/app_color_scheme.dart b/flutter_monisuo/lib/core/theme/app_color_scheme.dart index 16b79b4..f3dff55 100644 --- a/flutter_monisuo/lib/core/theme/app_color_scheme.dart +++ b/flutter_monisuo/lib/core/theme/app_color_scheme.dart @@ -133,6 +133,30 @@ class AppColorScheme { static const Color lightOnSurfaceVariant = Color(0xFF475569); static const Color lightOnSurfaceMuted = Color(0xFF94A3B8); + // ============================================ + // 精選卡片漸變色 (Featured Card Gradients) + // ============================================ + + /// BTC 卡片漸變 - 深藍色 (#1A1A2E → #0F3460) + static const LinearGradient btcCardGradient = LinearGradient( + colors: [Color(0xFF1A1A2E), Color(0xFF0F3460)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ); + + /// BTC 柱狀圖顏色 - 金色 + static const Color btcBarColor = Color(0xFFD4AF37); + + /// ETH 卡片漸變 - 深紫色 (#1A1040 → #312E81) + static const LinearGradient ethCardGradient = LinearGradient( + colors: [Color(0xFF1A1040), Color(0xFF312E81)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ); + + /// ETH 柱狀圖顏色 - 紫色 + static const Color ethBarColor = Color(0xFF818CF8); + // ============================================ // Glass Panel 毛玻璃效果顏色 // ============================================ diff --git a/flutter_monisuo/lib/ui/pages/asset/deposit_page.dart b/flutter_monisuo/lib/ui/pages/asset/deposit_page.dart index d84610a..71a014b 100644 --- a/flutter_monisuo/lib/ui/pages/asset/deposit_page.dart +++ b/flutter_monisuo/lib/ui/pages/asset/deposit_page.dart @@ -48,11 +48,11 @@ class _DepositPageState extends State { final text = _amountController.text; final n = double.tryParse(text); if (text.isEmpty || n == null || n <= 0) { - ToastUtils.showError('请输入有效金额'); + ToastUtils.showError('請輸入有效金額'); return; } if (n < 1000) { - ToastUtils.showError('单笔最低充值 1000 USDT'); + ToastUtils.showError('單筆最低充值 1000 USDT'); return; } if (_isSubmitting) return; @@ -75,10 +75,10 @@ class _DepositPageState extends State { response.data!['walletNetwork'] as String? ?? 'TRC20'; }); } else { - ToastUtils.showError(response.message ?? '申请失败'); + ToastUtils.showError(response.message ?? '申請失敗'); } } catch (e) { - if (mounted) ToastUtils.showError('申请失败: $e'); + if (mounted) ToastUtils.showError('申請失敗: $e'); } finally { if (mounted) setState(() => _isSubmitting = false); } @@ -90,8 +90,8 @@ class _DepositPageState extends State { final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( - title: const Text('确认已打款'), - content: const Text('确认您已完成向指定地址的转账?'), + title: const Text('確認已打款'), + content: const Text('確認您已完成向指定地址的轉賬?'), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), @@ -99,7 +99,7 @@ class _DepositPageState extends State { ), TextButton( onPressed: () => Navigator.pop(ctx, true), - child: const Text('确认'), + child: const Text('確認'), ), ], ), @@ -113,13 +113,13 @@ class _DepositPageState extends State { if (!mounted) return; if (response.success) { - ToastUtils.showSuccess('确认成功,请等待管理员审核'); + ToastUtils.showSuccess('確認成功,請等待管理員審核'); Navigator.of(context).pop(true); } else { - ToastUtils.showError(response.message ?? '确认失败'); + ToastUtils.showError(response.message ?? '確認失敗'); } } catch (e) { - if (mounted) ToastUtils.showError('确认失败: $e'); + if (mounted) ToastUtils.showError('確認失敗: $e'); } } @@ -230,7 +230,7 @@ class _DepositPageState extends State { Widget _buildAmountLabel(ColorScheme colorScheme) { return Text( - '充值金额', + '充值金額', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500, @@ -316,10 +316,10 @@ class _DepositPageState extends State { Widget _buildSteps(ColorScheme colorScheme) { final steps = [ - '输入充值金额并提交申请', - '向指定钱包地址转账', - '点击「已打款」确认', - '等待管理员审核通过', + '輸入充值金額並提交申請', + '向指定錢包地址轉賬', + '點擊「已打款」確認', + '等待管理員審核通過', ]; return Column( @@ -383,14 +383,14 @@ class _DepositPageState extends State { ), const SizedBox(height: 12), Text( - '充值申请成功', + '充值申請成功', style: AppTextStyles.headlineSmall(context).copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(height: 4), Text( - '请向以下地址转账完成充值', + '請向以下地址轉賬完成充值', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, ), @@ -419,7 +419,7 @@ class _DepositPageState extends State { const SizedBox(width: 6), Expanded( child: Text( - '转账完成后请点击「已打款」确认,管理员审核通过后资金将到账。', + '轉賬完成後請點擊「已打款」確認,管理員審核通過後資金將到賬。', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), @@ -445,7 +445,7 @@ class _DepositPageState extends State { ), ), child: Text( - '稍后确认', + '稍後確認', style: AppTextStyles.bodyMedium(context).copyWith( fontWeight: FontWeight.w500, ), @@ -502,7 +502,7 @@ class _DepositPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '订单号', + '訂單號', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), @@ -524,7 +524,7 @@ class _DepositPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '充值金额', + '充值金額', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), @@ -581,7 +581,7 @@ class _DepositPageState extends State { onTap: () { Clipboard.setData( ClipboardData(text: _walletAddress ?? '')); - ToastUtils.showSuccess('地址已复制'); + ToastUtils.showSuccess('地址已複製'); }, child: Padding( padding: const EdgeInsets.all(4), @@ -661,7 +661,7 @@ class _DepositPageState extends State { size: 13, color: colorScheme.onSurfaceVariant), const SizedBox(width: 4), Text( - '资金安全由平台全程保障', + '資金安全由平台全程保障', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), diff --git a/flutter_monisuo/lib/ui/pages/asset/transfer_page.dart b/flutter_monisuo/lib/ui/pages/asset/transfer_page.dart index ab46b4b..b5a4fb5 100644 --- a/flutter_monisuo/lib/ui/pages/asset/transfer_page.dart +++ b/flutter_monisuo/lib/ui/pages/asset/transfer_page.dart @@ -80,8 +80,8 @@ class _TransferPageState extends State { String get _availableBalance => _direction == 1 ? _fundBalance : _tradeUsdtBalance; - String get _fromLabel => _direction == 1 ? '资金账户' : '交易账户'; - String get _toLabel => _direction == 1 ? '交易账户' : '资金账户'; + String get _fromLabel => _direction == 1 ? '資金賬戶' : '交易賬戶'; + String get _toLabel => _direction == 1 ? '交易賬戶' : '資金賬戶'; String get _fromBalance => _direction == 1 ? _fundBalance : _tradeUsdtBalance; String get _toBalance => _direction == 1 ? _tradeUsdtBalance : _fundBalance; @@ -95,12 +95,12 @@ class _TransferPageState extends State { final transferAmount = double.tryParse(amount) ?? 0; if (transferAmount <= 0) { - _showSnackBar('请输入有效的划转金额'); + _showSnackBar('請輸入有效的劃轉金額'); return; } if (transferAmount > available) { - _showSnackBar('余额不足'); + _showSnackBar('餘額不足'); return; } @@ -115,11 +115,11 @@ class _TransferPageState extends State { if (mounted) { if (response.success) { _amountController.clear(); - _showSnackBar('划转成功'); + _showSnackBar('劃轉成功'); await Future.delayed(const Duration(milliseconds: 500)); if (mounted) Navigator.of(context).pop(true); } else { - _showSnackBar(response.message ?? '划转失败'); + _showSnackBar(response.message ?? '劃轉失敗'); } } } finally { @@ -171,7 +171,7 @@ class _TransferPageState extends State { onPressed: () => Navigator.of(context).pop(), ), title: Text( - '账户划转', + '賬戶劃轉', style: AppTextStyles.headlineLarge(context).copyWith( fontWeight: FontWeight.w600, ), @@ -339,7 +339,7 @@ class _TransferPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '划转金额', + '劃轉金額', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500, @@ -422,7 +422,7 @@ class _TransferPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '可用余额', + '可用餘額', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), @@ -492,7 +492,7 @@ class _TransferPageState extends State { size: 13, color: colorScheme.onSurfaceVariant), const SizedBox(width: 6), Text( - '划转即时到账,无需手续费', + '劃轉即時到賬,無需手續費', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), @@ -542,7 +542,7 @@ class _TransferPageState extends State { ), ) : Text( - '确认划转', + '確認劃轉', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, diff --git a/flutter_monisuo/lib/ui/pages/asset/withdraw_page.dart b/flutter_monisuo/lib/ui/pages/asset/withdraw_page.dart index ebc71db..7f35c76 100644 --- a/flutter_monisuo/lib/ui/pages/asset/withdraw_page.dart +++ b/flutter_monisuo/lib/ui/pages/asset/withdraw_page.dart @@ -63,20 +63,20 @@ class _WithdrawPageState extends State { if (amount > 0) { final fee = amount * 0.1; final receivable = amount - fee; - return '手续费(10%): -${fee.toStringAsFixed(2)} USDT | 应收款: ${receivable.toStringAsFixed(2)} USDT'; + return '手續費(10%): -${fee.toStringAsFixed(2)} USDT | 應收款: ${receivable.toStringAsFixed(2)} USDT'; } - return '提现将扣除 10% 手续费'; + return '提現將扣除 10% 手續費'; } Future _submitWithdraw() async { final amount = double.tryParse(_amountController.text); if (amount == null || amount <= 0) { - ToastUtils.showError('请输入有效金额'); + ToastUtils.showError('請輸入有效金額'); return; } final address = _addressController.text.trim(); if (address.isEmpty) { - ToastUtils.showError('请输入提现地址'); + ToastUtils.showError('請輸入提現地址'); return; } if (_isSubmitting) return; @@ -94,13 +94,13 @@ class _WithdrawPageState extends State { if (!mounted) return; if (response.success) { - ToastUtils.showSuccess('申请成功,请等待管理员审批'); + ToastUtils.showSuccess('申請成功,請等待管理員審批'); Navigator.of(context).pop(true); } else { - ToastUtils.showError(response.message ?? '申请失败'); + ToastUtils.showError(response.message ?? '申請失敗'); } } catch (e) { - if (mounted) ToastUtils.showError('申请失败: $e'); + if (mounted) ToastUtils.showError('申請失敗: $e'); } finally { if (mounted) setState(() => _isSubmitting = false); } @@ -123,7 +123,7 @@ class _WithdrawPageState extends State { onPressed: () => Navigator.of(context).pop(), ), title: Text( - '提现', + '提現', style: AppTextStyles.headlineLarge(context).copyWith( fontWeight: FontWeight.w600, ), @@ -146,7 +146,7 @@ class _WithdrawPageState extends State { ], // 提现金额 - _buildSectionLabel(colorScheme, '提现金额'), + _buildSectionLabel(colorScheme, '提現金額'), const SizedBox(height: AppSpacing.sm), _buildAmountInput(colorScheme), const SizedBox(height: AppSpacing.sm), @@ -157,20 +157,20 @@ class _WithdrawPageState extends State { // 提现网络 if (_networks.isNotEmpty) ...[ - _buildSectionLabel(colorScheme, '提现网络'), + _buildSectionLabel(colorScheme, '提現網絡'), const SizedBox(height: AppSpacing.sm), _buildNetworkSelector(colorScheme), const SizedBox(height: AppSpacing.lg), ], // 目标地址 - _buildSectionLabel(colorScheme, '目标地址'), + _buildSectionLabel(colorScheme, '目標地址'), const SizedBox(height: AppSpacing.sm), _buildAddressInput(colorScheme), const SizedBox(height: AppSpacing.lg), // 联系方式 - _buildSectionLabel(colorScheme, '联系方式(可选)'), + _buildSectionLabel(colorScheme, '聯繫方式(可選)'), const SizedBox(height: AppSpacing.sm), _buildContactInput(colorScheme), const SizedBox(height: AppSpacing.xl), @@ -210,7 +210,7 @@ class _WithdrawPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '可用余额', + '可用餘額', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, ), @@ -332,7 +332,7 @@ class _WithdrawPageState extends State { value: _selectedNetwork, isExpanded: true, hint: Text( - '选择提现网络', + '選擇提現網絡', style: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant, ), @@ -369,7 +369,7 @@ class _WithdrawPageState extends State { controller: _addressController, style: AppTextStyles.bodyMedium(context), decoration: InputDecoration( - hintText: '请输入提现地址', + hintText: '請輸入提現地址', hintStyle: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), @@ -399,7 +399,7 @@ class _WithdrawPageState extends State { controller: _contactController, style: AppTextStyles.bodyMedium(context), decoration: InputDecoration( - hintText: '方便客服与您联系', + hintText: '方便客服與您聯繫', hintStyle: AppTextStyles.bodyMedium(context).copyWith( color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), @@ -413,9 +413,9 @@ class _WithdrawPageState extends State { Widget _buildSecurityTips(ColorScheme colorScheme) { final tips = [ - '请仔细核对提现地址,地址错误将导致资产无法找回', - '提现申请提交后需等待管理员审批', - '提现将扣除 10% 手续费', + '請仔細核對提現地址,地址錯誤將導致資產無法找回', + '提現申請提交後需等待管理員審批', + '提現將扣除 10% 手續費', ]; return Column( @@ -475,7 +475,7 @@ class _WithdrawPageState extends State { ), ) : Text( - '提交申请', + '提交申請', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, @@ -494,7 +494,7 @@ class _WithdrawPageState extends State { size: 13, color: colorScheme.onSurfaceVariant), const SizedBox(width: 4), Text( - '资金安全由平台全程保障', + '資金安全由平台全程保障', style: AppTextStyles.bodySmall(context).copyWith( color: colorScheme.onSurfaceVariant, ), diff --git a/flutter_monisuo/lib/ui/pages/market/market_page.dart b/flutter_monisuo/lib/ui/pages/market/market_page.dart index 02b6d42..ef23582 100644 --- a/flutter_monisuo/lib/ui/pages/market/market_page.dart +++ b/flutter_monisuo/lib/ui/pages/market/market_page.dart @@ -2,12 +2,12 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:provider/provider.dart'; +import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_theme.dart'; import '../../../core/theme/app_theme_extension.dart'; import '../../../data/models/coin.dart'; import '../../../providers/market_provider.dart'; -import '../../components/glass_panel.dart'; import '../../components/coin_icon.dart'; import '../main/main_page.dart'; @@ -64,21 +64,21 @@ class _MarketPageState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ // 頁面標題 "行情" - Padding( - padding: const EdgeInsets.only(bottom: AppSpacing.sm), - child: Text( - '行情', - style: AppTextStyles.displaySmall(context), + Text( + '行情', + style: AppTextStyles.displaySmall(context).copyWith( + fontSize: 24, + fontWeight: FontWeight.w800, ), ), const SizedBox(height: AppSpacing.md), + // 搜索框 + _buildSearchBar(context), + const SizedBox(height: AppSpacing.md), // 精選區域:BTC + ETH 卡片 _buildFeaturedSection(provider), const SizedBox(height: AppSpacing.md), - // 分區標題:全部幣種 + 更多 - _buildSectionHeader(), - const SizedBox(height: AppSpacing.md), - // 幣種列表卡片 + // 全部幣種列表(含表頭) _buildCoinList(provider), ], ), @@ -89,6 +89,39 @@ class _MarketPageState extends State ); } + /// 搜索框 + Widget _buildSearchBar(BuildContext context) { + return GestureDetector( + onTap: () { + // TODO: 彈出搜索界面 + }, + child: Container( + height: 40, + decoration: BoxDecoration( + color: context.colors.surfaceContainerHigh, + borderRadius: BorderRadius.circular(AppRadius.md), + ), + padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md), + child: Row( + children: [ + Icon( + LucideIcons.search, + size: 16, + color: context.colors.onSurfaceVariant, + ), + const SizedBox(width: AppSpacing.sm), + Text( + '搜索幣種名稱或代碼', + style: AppTextStyles.bodyMedium(context).copyWith( + color: context.appColors.onSurfaceMuted, + ), + ), + ], + ), + ), + ); + } + /// 精選區域:BTC + ETH 大卡片 Widget _buildFeaturedSection(MarketProvider provider) { final featured = provider.featuredCoins; @@ -103,7 +136,7 @@ class _MarketPageState extends State Expanded(child: _FeaturedCard(coin: btc)) else const Expanded(child: SizedBox.shrink()), - const SizedBox(width: AppSpacing.sm + AppSpacing.xs), + const SizedBox(width: 10), if (eth != null) Expanded(child: _FeaturedCard(coin: eth)) else @@ -112,26 +145,7 @@ class _MarketPageState extends State ); } - /// 分區標題:全部幣種 + 更多 - Widget _buildSectionHeader() { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '全部幣種', - style: AppTextStyles.headlineLarge(context), - ), - Text( - '更多 >', - style: AppTextStyles.bodyMedium(context).copyWith( - color: context.colors.onSurfaceVariant, - ), - ), - ], - ); - } - - /// 幣種列表 + /// 幣種列表(含表頭) Widget _buildCoinList(MarketProvider provider) { final coins = provider.otherCoins; @@ -152,18 +166,77 @@ class _MarketPageState extends State width: 1, ), ), - child: ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: coins.length, - separatorBuilder: (_, __) => Divider( - height: 1, - thickness: 1, - color: context.colors.outlineVariant.withValues(alpha: 0.5 * 0.15), - indent: AppSpacing.md, - endIndent: AppSpacing.md, - ), - itemBuilder: (context, index) => _CoinRow(coin: coins[index]), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 表頭行 + _buildListHeader(context), + // 列表項 + ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: coins.length, + separatorBuilder: (_, __) => Divider( + height: 1, + thickness: 1, + color: context.colors.outlineVariant.withValues(alpha: 0.5 * 0.15), + indent: AppSpacing.md, + endIndent: AppSpacing.md, + ), + itemBuilder: (context, index) => _CoinRow(coin: coins[index]), + ), + ], + ), + ); + } + + /// 列表表頭行:幣種 | 最新價 | 漲跌幅 + Widget _buildListHeader(BuildContext context) { + return const Padding( + padding: EdgeInsets.fromLTRB( + AppSpacing.md, + AppSpacing.sm + AppSpacing.xs, + AppSpacing.md, + AppSpacing.sm, + ), + child: Row( + children: [ + Expanded( + child: Text( + '幣種', + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: AppColorScheme.darkOnSurfaceVariant, + ), + ), + ), + SizedBox( + width: 90, + child: Text( + '最新價', + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: AppColorScheme.darkOnSurfaceVariant, + ), + ), + ), + SizedBox(width: AppSpacing.sm), + SizedBox( + width: 72, + child: Text( + '漲跌幅', + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w600, + color: AppColorScheme.darkOnSurfaceVariant, + ), + ), + ), + ], ), ); } @@ -195,7 +268,7 @@ class _MarketPageState extends State } } -/// 精選卡片:BTC / ETH (130px 高度,含迷你柱狀圖) +/// 精選卡片:BTC / ETH (148px 高度,漸變背景,含迷你柱狀圖) class _FeaturedCard extends StatelessWidget { final Coin coin; @@ -204,60 +277,78 @@ class _FeaturedCard extends StatelessWidget { @override Widget build(BuildContext context) { final isUp = coin.isUp; - final changeColor = - isUp ? context.appColors.up : context.appColors.down; - final changeBgColor = isUp - ? context.appColors.upBackground - : context.appColors.downBackground; + final isBtc = coin.code == 'BTC'; - return GlassPanel( + final gradient = + isBtc ? AppColorScheme.btcCardGradient : AppColorScheme.ethCardGradient; + final barColor = + isBtc ? AppColorScheme.btcBarColor : AppColorScheme.ethBarColor; + final changeBgColor = isUp + ? AppColorScheme.darkTertiary.withValues(alpha: 0.2) + : AppColorScheme.darkError.withValues(alpha: 0.2); + final changeColor = isUp + ? AppColorScheme.darkTertiary + : AppColorScheme.darkError; + + return Container( + height: 148, padding: const EdgeInsets.all(AppSpacing.md), - height: 130, + decoration: BoxDecoration( + gradient: gradient, + borderRadius: BorderRadius.circular(AppRadius.lg), + ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - // 第一行:幣種名稱 + 漲跌徽章 + // 第一行:交易對名 + 漲跌幅標籤 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '${coin.code}/USDT', - style: AppTextStyles.labelLarge(context), // 縮小文字 + style: const TextStyle( + color: Colors.white, + fontSize: 13, + fontWeight: FontWeight.w600, + ), ), Container( - padding: const EdgeInsets.symmetric(horizontal: AppSpacing.xs + 2, vertical: 2), + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.xs + 2, + vertical: 2, + ), decoration: BoxDecoration( color: changeBgColor, - borderRadius: BorderRadius.circular(AppRadius.sm), + borderRadius: BorderRadius.circular(4), ), child: Text( coin.formattedChange, - style: AppTextStyles.labelSmall(context).copyWith( + style: TextStyle( color: changeColor, - fontSize: 10, // 縮小文字 + fontSize: 10, + fontWeight: FontWeight.w600, ), ), ), ], ), - // 第二行:價格 + // 第二行:大號價格 Text( '\$${_formatFeaturedPrice(coin)}', - style: AppTextStyles.headlineLarge(context).copyWith( // 縮小文字 - fontWeight: FontWeight.bold, + style: const TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.w800, + height: 1.2, ), ), - // 第三行:幣種全名 - Text( - coin.name, - style: AppTextStyles.bodySmall(context).copyWith( // 縮小文字 - color: context.colors.onSurfaceVariant, - ), - ), - // 第四行:迷你柱狀圖 + // 第三行:迷你柱狀圖 Expanded( - child: _MiniBarChart(isUp: isUp, seed: coin.code.hashCode), + child: _MiniBarChart( + barColor: barColor, + seed: coin.code.hashCode, + ), ), ], ), @@ -291,17 +382,13 @@ class _FeaturedCard extends StatelessWidget { /// 迷你柱狀圖(模擬價格走勢) class _MiniBarChart extends StatelessWidget { - final bool isUp; + final Color barColor; final int seed; - const _MiniBarChart({required this.isUp, required this.seed}); + const _MiniBarChart({required this.barColor, required this.seed}); @override Widget build(BuildContext context) { - final barColor = isUp - ? context.appColors.up - : context.appColors.down; - // 生成隨機但確定的高度序列 final heights = _generateHeights(); @@ -311,7 +398,7 @@ class _MiniBarChart extends StatelessWidget { children: heights.map((h) { return Expanded( child: Padding( - padding: const EdgeInsets.only(left: 2), // 增加間距 + padding: const EdgeInsets.only(left: 2), child: Container( height: h, decoration: BoxDecoration( @@ -327,8 +414,8 @@ class _MiniBarChart extends StatelessWidget { List _generateHeights() { final random = Random(seed); - final base = 6.0; // 降低基礎高度 - final range = 12.0; // 降低範圍 + const base = 6.0; + const range = 12.0; return List.generate(6, (_) => base + random.nextDouble() * range); } } @@ -352,11 +439,18 @@ class _CoinRow extends StatelessWidget { onTap: () => _navigateToTrade(context), behavior: HitTestBehavior.opaque, child: Padding( - padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md, vertical: 14), + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.md, + vertical: 14, + ), child: Row( children: [ - // 頭像:圓形字母頭像 - _CoinAvatar(letter: coin.displayIcon, code: coin.code), + // 頭像:36px 圓形 + CoinIcon( + symbol: coin.code, + size: 36, + isCircle: true, + ), const SizedBox(width: AppSpacing.sm + AppSpacing.xs), // 幣種信息:交易對 + 全名 Expanded( @@ -366,7 +460,9 @@ class _CoinRow extends StatelessWidget { children: [ Text( '${coin.code}/USDT', - style: AppTextStyles.numberMedium(context), + style: AppTextStyles.numberMedium(context).copyWith( + fontWeight: FontWeight.w600, + ), ), const SizedBox(height: 2), Text( @@ -376,30 +472,36 @@ class _CoinRow extends StatelessWidget { ], ), ), - // 右側:價格 + 漲跌標籤 - Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - '\$${coin.formattedPrice}', - style: AppTextStyles.numberMedium(context), + // 價格(固定寬度90,右對齊) + SizedBox( + width: 90, + child: Text( + '\$${coin.formattedPrice}', + textAlign: TextAlign.right, + style: AppTextStyles.numberMedium(context), + ), + ), + const SizedBox(width: AppSpacing.sm), + // 漲跌幅標籤(固定寬度72) + SizedBox( + width: 72, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.xs + 2, + vertical: 4, ), - const SizedBox(height: 2), - Container( - padding: const EdgeInsets.symmetric(horizontal: AppSpacing.xs + 2, vertical: 2), - decoration: BoxDecoration( - color: changeBgColor, - borderRadius: BorderRadius.circular(AppRadius.sm), - ), - child: Text( - coin.formattedChange, - style: AppTextStyles.labelMedium(context).copyWith( - color: changeColor, - ), + decoration: BoxDecoration( + color: changeBgColor, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + coin.formattedChange, + textAlign: TextAlign.center, + style: AppTextStyles.labelSmall(context).copyWith( + color: changeColor, ), ), - ], + ), ), ], ), @@ -413,31 +515,17 @@ class _CoinRow extends StatelessWidget { } } -/// 幣種頭像組件 -class _CoinAvatar extends StatelessWidget { - final String letter; - final String code; - - const _CoinAvatar({required this.letter, required this.code}); - - @override - Widget build(BuildContext context) { - // 使用新的 CoinIcon 组件 - return CoinIcon( - symbol: code, - size: 36, - isCircle: true, - ); - } -} - /// 空狀態 class _EmptyState extends StatelessWidget { final IconData icon; final String message; final VoidCallback? onRetry; - const _EmptyState({required this.icon, required this.message, this.onRetry}); + const _EmptyState({ + required this.icon, + required this.message, + this.onRetry, + }); @override Widget build(BuildContext context) {