refactor(theme): 迁移主题感知颜色至 ThemeExtension

- 创建 AppThemeColors ThemeExtension 类,统一管理主题感知颜色(涨跌色、卡片背景、渐变等)
- 从 AppColorScheme 移除主题感知辅助函数,仅保留静态颜色常量
- 在 AppTheme 中注册 ThemeExtension,支持深色/浅色主题工厂
- 重构所有 UI 组件使用 context.appColors 访问主题颜色,替代硬编码的 AppColorScheme 方法调用
- 移除组件中重复的 isDark 判断逻辑,简化颜色获取方式
- 保持向后兼容性,所有现有功能不变
This commit is contained in:
2026-04-06 01:58:08 +08:00
parent 396668aa43
commit 7ed2435a4c
36 changed files with 658 additions and 810 deletions

View File

@@ -2,9 +2,9 @@ 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';
@@ -34,10 +34,9 @@ class _MarketPageState extends State<MarketPage>
@override
Widget build(BuildContext context) {
super.build(context);
final colorScheme = Theme.of(context).colorScheme;
return Scaffold(
backgroundColor: colorScheme.background,
backgroundColor: context.colors.surface,
body: Consumer<MarketProvider>(
builder: (context, provider, _) {
if (provider.isLoading) {
@@ -50,8 +49,8 @@ class _MarketPageState extends State<MarketPage>
return RefreshIndicator(
onRefresh: () => provider.refresh(),
color: colorScheme.primary,
backgroundColor: colorScheme.surfaceContainerHighest,
color: context.colors.primary,
backgroundColor: context.colors.surfaceContainerHighest,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.only(
@@ -114,8 +113,6 @@ class _MarketPageState extends State<MarketPage>
/// 分区标题:全部币种 + 更多
Widget _buildSectionHeader() {
final colorScheme = Theme.of(context).colorScheme;
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -126,7 +123,7 @@ class _MarketPageState extends State<MarketPage>
Text(
'更多 >',
style: AppTextStyles.bodyMedium(context).copyWith(
color: colorScheme.onSurfaceVariant,
color: context.colors.onSurfaceVariant,
),
),
],
@@ -136,7 +133,6 @@ class _MarketPageState extends State<MarketPage>
/// 币种列表
Widget _buildCoinList(MarketProvider provider) {
final coins = provider.otherCoins;
final colorScheme = Theme.of(context).colorScheme;
if (coins.isEmpty) {
return _EmptyState(
@@ -148,10 +144,10 @@ class _MarketPageState extends State<MarketPage>
return Container(
decoration: BoxDecoration(
color: colorScheme.surfaceContainer,
color: context.colors.surfaceContainer,
borderRadius: BorderRadius.circular(AppRadius.lg),
border: Border.all(
color: colorScheme.outlineVariant.withValues(alpha: 0.15),
color: context.appColors.ghostBorder,
width: 1,
),
),
@@ -162,7 +158,7 @@ class _MarketPageState extends State<MarketPage>
separatorBuilder: (_, __) => Divider(
height: 1,
thickness: 1,
color: colorScheme.outlineVariant.withValues(alpha: 0.5 * 0.15),
color: context.colors.outlineVariant.withValues(alpha: 0.5 * 0.15),
indent: AppSpacing.md,
endIndent: AppSpacing.md,
),
@@ -173,18 +169,17 @@ class _MarketPageState extends State<MarketPage>
/// 错误状态
Widget _buildErrorState(MarketProvider provider) {
final colorScheme = Theme.of(context).colorScheme;
return Center(
child: Padding(
padding: AppSpacing.pagePadding,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(LucideIcons.circleAlert, size: 48, color: colorScheme.error),
Icon(LucideIcons.circleAlert, size: 48, color: context.colors.error),
const SizedBox(height: AppSpacing.md),
Text(
provider.error ?? '加载失败',
style: TextStyle(color: colorScheme.error),
style: TextStyle(color: context.colors.error),
textAlign: TextAlign.center,
),
const SizedBox(height: AppSpacing.md),
@@ -207,14 +202,12 @@ class _FeaturedCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
final isUp = coin.isUp;
final changeColor =
isUp ? AppColorScheme.getUpColor(isDark) : AppColorScheme.down;
isUp ? context.appColors.up : context.appColors.down;
final changeBgColor = isUp
? AppColorScheme.getUpBackgroundColor(isDark)
: AppColorScheme.getDownBackgroundColor(isDark);
? context.appColors.upBackground
: context.appColors.downBackground;
return GlassPanel(
padding: const EdgeInsets.all(AppSpacing.md),
@@ -255,12 +248,12 @@ class _FeaturedCard extends StatelessWidget {
Text(
coin.name,
style: AppTextStyles.bodyMedium(context).copyWith(
color: colorScheme.onSurfaceVariant,
color: context.colors.onSurfaceVariant,
),
),
// 第四行:迷你柱状图
Expanded(
child: _MiniBarChart(isUp: isUp, isDark: isDark, seed: coin.code.hashCode),
child: _MiniBarChart(isUp: isUp, seed: coin.code.hashCode),
),
],
),
@@ -295,16 +288,15 @@ class _FeaturedCard extends StatelessWidget {
/// 迷你柱状图(模拟价格走势)
class _MiniBarChart extends StatelessWidget {
final bool isUp;
final bool isDark;
final int seed;
const _MiniBarChart({required this.isUp, required this.isDark, required this.seed});
const _MiniBarChart({required this.isUp, required this.seed});
@override
Widget build(BuildContext context) {
final barColor = isUp
? AppColorScheme.getUpColor(isDark)
: AppColorScheme.getDownColor(isDark);
? context.appColors.up
: context.appColors.down;
// 生成随机但确定的高度序列
final heights = _generateHeights();
@@ -345,14 +337,12 @@ class _CoinRow extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
final isUp = coin.isUp;
final changeColor =
isUp ? AppColorScheme.getUpColor(isDark) : AppColorScheme.getDownColor(isDark);
isUp ? context.appColors.up : context.appColors.down;
final changeBgColor = isUp
? AppColorScheme.getUpBackgroundColor(isDark)
: AppColorScheme.getDownBackgroundColor(isDark);
? context.appColors.upBackground
: context.appColors.downBackground;
return GestureDetector(
onTap: () => _navigateToTrade(context),
@@ -428,12 +418,8 @@ class _CoinAvatar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
// 从 .pen 设计中的 accent-light 和 accent-primary
final bgColor = colorScheme.primary.withValues(alpha: isDark ? 0.15 : 0.1);
final textColor = colorScheme.primary;
final bgColor = context.colors.primary.withValues(alpha: context.appColors.glowOpacity);
return Container(
width: 36,
@@ -447,7 +433,7 @@ class _CoinAvatar extends StatelessWidget {
_getLetter(),
style: AppTextStyles.labelLarge(context).copyWith(
fontWeight: FontWeight.w700,
color: textColor,
color: context.colors.primary,
),
),
),
@@ -477,18 +463,16 @@ class _EmptyState extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Center(
child: Padding(
padding: const EdgeInsets.all(AppSpacing.xl),
child: Column(
children: [
Icon(icon, size: 48, color: colorScheme.onSurfaceVariant),
Icon(icon, size: 48, color: context.colors.onSurfaceVariant),
const SizedBox(height: AppSpacing.sm + AppSpacing.xs),
Text(
message,
style: TextStyle(color: colorScheme.onSurfaceVariant),
style: TextStyle(color: context.colors.onSurfaceVariant),
),
if (onRetry != null) ...[
const SizedBox(height: AppSpacing.md),