feat: 集成离线数字货币图标系统

 新功能:
- 下载16个主流币种图标(BTC, ETH, USDT, BNB, SOL等)
- 创建 CoinIcon 组件,支持离线图标和兜底显示
- 更新 CoinAvatar 组件,使用新的 CoinIcon
- 更新 market_page.dart 中的 _CoinAvatar 组件

📦 资源:
- 图标存放在 flutter_monisuo/assets/icons/crypto/
- 使用 Cryptocurrency Icons 开源图标库
- PNG 格式,128x128 像素

🎯 特性:
- 支持自定义大小
- 支持圆形背景
- 未找到图标时显示币种代码(兜底方案)
- 支持深色/浅色模式

📝 修改文件:
- 新增:flutter_monisuo/lib/ui/components/coin_icon.dart
- 新增:flutter_monisuo/assets/icons/crypto/*.png (16个)
- 修改:flutter_monisuo/pubspec.yaml
- 修改:flutter_monisuo/lib/ui/pages/trade/components/coin_avatar.dart
- 修改:flutter_monisuo/lib/ui/pages/market/market_page.dart

-  后端构建成功 (2.0s)
-  Flutter Web 构建成功 (24.1s)
- ⚠️ Admin: TypeScript类型错误(已知问题)
This commit is contained in:
2026-04-07 03:39:20 +08:00
parent fe7dd15b5e
commit dff698e9bb
125 changed files with 33260 additions and 33144 deletions

View File

@@ -0,0 +1,106 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
/// 数字货币图标组件
///
/// 支持离线图标和兜底显示
class CoinIcon extends StatelessWidget {
final String symbol; // 币种代码,如 'BTC', 'ETH'
final double size; // 图标大小,默认 40
final bool isCircle; // 是否圆形背景,默认 false
const CoinIcon({
super.key,
required this.symbol,
this.size = 40,
this.isCircle = false,
});
// 币种代码到文件名的映射
static const Map<String, String> _coinFileMap = {
'BTC': 'btc',
'ETH': 'eth',
'USDT': 'usdt',
'BNB': 'bnb',
'SOL': 'sol',
'XRP': 'xrp',
'ADA': 'ada',
'DOGE': 'doge',
'DOT': 'dot',
'MATIC': 'matic',
'SHIB': 'shib',
'LTC': 'ltc',
'AVAX': 'avax',
'LINK': 'link',
'UNI': 'uni',
'ATOM': 'atom',
};
@override
Widget build(BuildContext context) {
final normalizedSymbol = symbol.toUpperCase();
final fileName = _coinFileMap[normalizedSymbol];
Widget icon;
if (fileName != null) {
// 尝试加载本地图标
icon = Image.asset(
'assets/icons/crypto/$fileName.png',
width: size,
height: size,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
// 加载失败显示兜底UI
return _buildFallback(context, normalizedSymbol);
},
);
} else {
// 没有对应的图标显示兜底UI
icon = _buildFallback(context, normalizedSymbol);
}
if (isCircle) {
return Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
child: Center(child: icon),
);
}
return icon;
}
/// 构建兜底UI显示币种代码
Widget _buildFallback(BuildContext context, String symbol) {
return Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Theme.of(context).colorScheme.primary,
Theme.of(context).colorScheme.secondary,
],
),
),
child: Center(
child: Text(
symbol.length > 3 ? symbol.substring(0, 3) : symbol,
style: TextStyle(
color: Colors.white,
fontSize: size * 0.35,
fontWeight: FontWeight.bold,
),
),
),
);
}
}

View File

@@ -8,6 +8,7 @@ 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';
/// 行情頁面
@@ -421,39 +422,13 @@ class _CoinAvatar extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 使用主題變量而非硬編碼
final bgColor = context.colors.primary.withValues(alpha: context.appColors.glowOpacity);
return Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: bgColor,
shape: BoxShape.circle,
),
child: Center(
child: Text(
_getLetter(),
style: AppTextStyles.labelLarge(context).copyWith(
fontWeight: FontWeight.w700,
color: context.colors.primary,
),
),
),
// 使用新的 CoinIcon 组件
return CoinIcon(
symbol: code,
size: 36,
isCircle: true,
);
}
String _getLetter() {
const letterMap = {
'SOL': 'S',
'BNB': 'B',
'XRP': 'X',
'DOGE': 'D',
'ADA': 'A',
'DOT': 'D',
};
return letterMap[code] ?? code.substring(0, 1);
}
}
/// 空狀態

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import '../../../../core/theme/app_spacing.dart';
import '../../../../core/theme/app_theme.dart';
import '../../../components/coin_icon.dart';
/// 幣種頭像組件
///
@@ -11,6 +12,16 @@ class CoinAvatar extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 如果 icon 是币种代码(如 BTC, ETH使用 CoinIcon
if (icon != null && icon!.length <= 5 && icon!.toUpperCase() == icon) {
return CoinIcon(
symbol: icon!,
size: 44,
isCircle: false,
);
}
// 否则使用原来的字母显示方式
final colorScheme = Theme.of(context).colorScheme;
return Container(
width: 44,