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

@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:flutter_animate/flutter_animate.dart';
import '../../core/theme/app_color_scheme.dart';
import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme_extension.dart';
/// 资产卡片组件 - 用于显示资产总览
///
@@ -21,24 +21,6 @@ class AssetCard extends StatelessWidget {
final Gradient? gradient;
final VoidCallback? onTap;
/// 默认渐变色 - Neon Blue → Electric Purple
static LinearGradient defaultGradientBuilder(bool isDark) => LinearGradient(
colors: isDark
? [AppColorScheme.darkPrimary, AppColorScheme.darkSecondary]
: [AppColorScheme.lightPrimary, AppColorScheme.lightSecondary],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
/// 翡翠渐变 - 用于盈利展示(主题感知)
static LinearGradient getEmeraldGradient(bool isDark) => LinearGradient(
colors: isDark
? [AppColorScheme.darkTertiary, const Color(0xFF7de8b8)]
: [AppColorScheme.lightTertiary, const Color(0xFF00c987)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
);
const AssetCard({
super.key,
this.title = '总资产',
@@ -54,9 +36,9 @@ class AssetCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = ShadTheme.of(context);
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
final cardGradient = gradient ?? defaultGradientBuilder(isDark);
final colorScheme = context.colors;
final appColors = context.appColors;
final cardGradient = gradient ?? appColors.assetGradient;
// 主题感知颜色 - 在渐变背景上使用 onPrimary
final primaryTextColor = colorScheme.onPrimary;
@@ -197,6 +179,7 @@ class AssetCardCompact extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = ShadTheme.of(context);
final appColors = context.appColors;
final isValueUp = isUp ?? true;
return ShadCard(
@@ -227,13 +210,13 @@ class AssetCardCompact extends StatelessWidget {
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
decoration: BoxDecoration(
color: AppColorScheme.getChangeBackgroundColor(isValueUp),
color: isValueUp ? appColors.upBackground : appColors.downBackground,
borderRadius: BorderRadius.circular(AppRadius.sm),
),
child: Text(
change!,
style: TextStyle(
color: AppColorScheme.getChangeColor(isValueUp),
color: isValueUp ? appColors.up : appColors.down,
fontWeight: FontWeight.w600,
),
),

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import '../../core/theme/app_color_scheme.dart';
import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme_extension.dart';
/// 币种卡片组件 - 用于显示币种信息
///
@@ -81,13 +81,13 @@ class CoinCard extends StatelessWidget {
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
decoration: BoxDecoration(
color: AppColorScheme.getChangeBackgroundColor(isUp),
color: isUp ? context.appColors.upBackground : context.appColors.downBackground,
borderRadius: BorderRadius.circular(AppRadius.sm),
),
child: Text(
change,
style: TextStyle(
color: AppColorScheme.getChangeColor(isUp),
color: isUp ? context.appColors.up : context.appColors.down,
fontWeight: FontWeight.w600,
),
),

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme_extension.dart';
/// GlassPanel - 实心背景面板
///
@@ -55,11 +56,8 @@ class GlassPanel extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
final bgColor = backgroundColor ??
(isDark ? colorScheme.surfaceContainer : colorScheme.surfaceContainerHigh);
final brColor = borderColor ?? colorScheme.outlineVariant.withOpacity(0.15);
final bgColor = backgroundColor ?? context.appColors.surfaceCard;
final brColor = borderColor ?? context.appColors.ghostBorder;
final br = borderRadius ?? BorderRadius.circular(AppRadius.xl);
Widget content = Container(
@@ -133,11 +131,9 @@ class GlassCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
final br = borderRadius ?? BorderRadius.circular(AppRadius.xl);
final glowColor = neonGlowColor ??
colorScheme.primary.withOpacity(isDark ? 0.15 : 0.08);
context.colors.primary.withValues(alpha: context.appColors.glowOpacity);
Widget card = GlassPanel(
padding: padding ?? EdgeInsets.all(AppSpacing.md),
@@ -200,17 +196,14 @@ class GlassBottomSheet extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
return Container(
decoration: BoxDecoration(
color: isDark ? colorScheme.surfaceContainer : colorScheme.surfaceContainerHigh,
color: context.appColors.surfaceCard,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(AppRadius.xxl),
),
border: Border.all(
color: colorScheme.outlineVariant.withOpacity(0.15),
color: context.appColors.ghostBorder,
),
),
child: Column(
@@ -222,7 +215,7 @@ class GlassBottomSheet extends StatelessWidget {
width: 40,
height: 4,
decoration: BoxDecoration(
color: colorScheme.outlineVariant.withOpacity(0.5),
color: context.colors.outlineVariant.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(2),
),
),
@@ -244,7 +237,7 @@ class GlassBottomSheet extends StatelessWidget {
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: colorScheme.onSurface,
color: context.colors.onSurface,
),
),
),
@@ -254,14 +247,14 @@ class GlassBottomSheet extends StatelessWidget {
child: Container(
padding: EdgeInsets.all(AppSpacing.sm),
decoration: BoxDecoration(
color: colorScheme.outlineVariant
color: context.colors.outlineVariant
.withOpacity(0.2),
shape: BoxShape.circle,
),
child: Icon(
Icons.close,
size: 18,
color: colorScheme.onSurfaceVariant,
color: context.colors.onSurfaceVariant,
),
),
),

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import '../../core/theme/app_color_scheme.dart';
import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme_extension.dart';
/// 渐变按钮组件 - 支持 CTA 渐变效果
///
@@ -36,7 +36,6 @@ class GradientButton extends StatelessWidget {
bool isLoading = false,
bool isFullWidth = true,
IconData? icon,
bool isDark = true,
}) {
return GradientButton(
key: key,
@@ -45,7 +44,6 @@ class GradientButton extends StatelessWidget {
isLoading: isLoading,
isFullWidth: isFullWidth,
icon: icon,
gradient: isDark ? AppColorScheme.darkCtaGradient : AppColorScheme.lightCtaGradient,
);
}
@@ -57,6 +55,7 @@ class GradientButton extends StatelessWidget {
bool isLoading = false,
bool isFullWidth = true,
IconData? icon,
LinearGradient? gradient,
}) {
return GradientButton(
key: key,
@@ -65,7 +64,6 @@ class GradientButton extends StatelessWidget {
isLoading: isLoading,
isFullWidth: isFullWidth,
icon: icon ?? Icons.arrow_downward_rounded,
gradient: AppColorScheme.buyGradient,
);
}
@@ -77,6 +75,7 @@ class GradientButton extends StatelessWidget {
bool isLoading = false,
bool isFullWidth = true,
IconData? icon,
LinearGradient? gradient,
}) {
return GradientButton(
key: key,
@@ -85,16 +84,14 @@ class GradientButton extends StatelessWidget {
isLoading: isLoading,
isFullWidth: isFullWidth,
icon: icon ?? Icons.arrow_upward_rounded,
gradient: AppColorScheme.sellGradient,
);
}
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final colorScheme = Theme.of(context).colorScheme;
final buttonGradient = gradient ??
(isDark ? AppColorScheme.darkCtaGradient : AppColorScheme.lightCtaGradient);
final appColors = context.appColors;
final colorScheme = context.colors;
final buttonGradient = gradient ?? appColors.ctaGradient;
// 主题感知颜色 - 在渐变背景上使用 onPrimary
final textColor = colorScheme.onPrimary;
@@ -172,11 +169,8 @@ class GhostButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final textColor = isDark ? AppColorScheme.darkPrimary : AppColorScheme.lightPrimary;
final borderColor = isDark
? AppColorScheme.darkOutlineVariant.withValues(alpha: 0.15)
: AppColorScheme.lightOutlineVariant.withValues(alpha: 0.3);
final textColor = context.colors.primary;
final borderColor = context.appColors.ghostBorder;
return Container(
width: isFullWidth ? double.infinity : null,

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import '../../core/theme/app_color_scheme.dart';
import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme_extension.dart';
/// NeonGlow - 霓虹光效组件
///
@@ -94,7 +95,7 @@ class NeonGlow extends StatelessWidget {
}) {
return NeonGlow(
key: key,
glowColor: AppColorScheme.down.withOpacity(0.3),
glowColor: AppColorScheme.down.withValues(alpha: 0.3),
blurRadius: blurRadius,
borderRadius: borderRadius,
child: child,
@@ -205,16 +206,15 @@ class _NeonButtonState extends State<NeonButton>
}
Color get _backgroundColor {
final isDark = Theme.of(context).brightness == Brightness.dark;
final colorScheme = Theme.of(context).colorScheme;
final colors = context.colors;
switch (widget.type) {
case NeonButtonType.primary:
return colorScheme.primary;
return colors.primary;
case NeonButtonType.secondary:
return colorScheme.secondary;
return colors.secondary;
case NeonButtonType.tertiary:
return AppColorScheme.getUpColor(isDark);
return context.appColors.up;
case NeonButtonType.error:
return AppColorScheme.down;
case NeonButtonType.outline:
@@ -223,38 +223,37 @@ class _NeonButtonState extends State<NeonButton>
}
Color get _foregroundColor {
final isDark = Theme.of(context).brightness == Brightness.dark;
final colorScheme = Theme.of(context).colorScheme;
final colors = context.colors;
switch (widget.type) {
case NeonButtonType.primary:
return isDark ? AppColorScheme.darkOnPrimary : const Color(0xFFFFFFFF);
return colors.onPrimary;
case NeonButtonType.secondary:
return isDark ? AppColorScheme.darkOnSecondary : const Color(0xFFFFFFFF);
return colors.onSecondary;
case NeonButtonType.tertiary:
return isDark ? AppColorScheme.darkOnTertiary : const Color(0xFFFFFFFF);
return colors.onTertiary;
case NeonButtonType.error:
return const Color(0xFFFFFFFF);
case NeonButtonType.outline:
return colorScheme.primary;
return colors.primary;
}
}
Color get _glowColor {
final isDark = Theme.of(context).brightness == Brightness.dark;
final colorScheme = Theme.of(context).colorScheme;
final colors = context.colors;
final appColors = context.appColors;
switch (widget.type) {
case NeonButtonType.primary:
return colorScheme.primary.withOpacity(isDark ? 0.15 : 0.08);
return colors.primary.withValues(alpha: appColors.glowOpacity);
case NeonButtonType.secondary:
return colorScheme.secondary.withOpacity(isDark ? 0.15 : 0.08);
return colors.secondary.withValues(alpha: appColors.glowOpacity);
case NeonButtonType.tertiary:
return AppColorScheme.getUpBackgroundColor(isDark, opacity: isDark ? 0.2 : 0.1);
return context.appColors.upBackground;
case NeonButtonType.error:
return AppColorScheme.down.withOpacity(0.3);
return AppColorScheme.down.withValues(alpha: 0.3);
case NeonButtonType.outline:
return colorScheme.primary.withOpacity(isDark ? 0.15 : 0.08);
return colors.primary.withValues(alpha: appColors.glowOpacity);
}
}
@@ -265,8 +264,7 @@ class _NeonButtonState extends State<NeonButton>
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
final colors = context.colors;
final button = GestureDetector(
onTapDown: widget.onPressed != null ? _onTapDown : null,
@@ -286,7 +284,7 @@ class _NeonButtonState extends State<NeonButton>
),
border: widget.type == NeonButtonType.outline
? Border.all(
color: colorScheme.outlineVariant.withOpacity(0.3),
color: colors.outlineVariant.withValues(alpha: 0.3),
)
: null,
),