- 创建 AppThemeColors ThemeExtension 类,统一管理主题感知颜色(涨跌色、卡片背景、渐变等) - 从 AppColorScheme 移除主题感知辅助函数,仅保留静态颜色常量 - 在 AppTheme 中注册 ThemeExtension,支持深色/浅色主题工厂 - 重构所有 UI 组件使用 context.appColors 访问主题颜色,替代硬编码的 AppColorScheme 方法调用 - 移除组件中重复的 isDark 判断逻辑,简化颜色获取方式 - 保持向后兼容性,所有现有功能不变
224 lines
5.9 KiB
Dart
224 lines
5.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../../core/theme/app_spacing.dart';
|
|
import '../../core/theme/app_theme_extension.dart';
|
|
|
|
/// 渐变按钮组件 - 支持 CTA 渐变效果
|
|
///
|
|
/// 设计规则:
|
|
/// - 渐变方向: 135度 (primary → primary_container)
|
|
/// - 圆角: xxl (24px / 1.5rem)
|
|
/// - 无边框
|
|
class GradientButton extends StatelessWidget {
|
|
final String text;
|
|
final VoidCallback? onPressed;
|
|
final bool isLoading;
|
|
final bool isFullWidth;
|
|
final LinearGradient? gradient;
|
|
final IconData? icon;
|
|
final double height;
|
|
|
|
const GradientButton({
|
|
super.key,
|
|
required this.text,
|
|
this.onPressed,
|
|
this.isLoading = false,
|
|
this.isFullWidth = true,
|
|
this.gradient,
|
|
this.icon,
|
|
this.height = 48,
|
|
});
|
|
|
|
/// CTA 按钮 - 使用主题渐变
|
|
factory GradientButton.cta({
|
|
Key? key,
|
|
required String text,
|
|
VoidCallback? onPressed,
|
|
bool isLoading = false,
|
|
bool isFullWidth = true,
|
|
IconData? icon,
|
|
}) {
|
|
return GradientButton(
|
|
key: key,
|
|
text: text,
|
|
onPressed: onPressed,
|
|
isLoading: isLoading,
|
|
isFullWidth: isFullWidth,
|
|
icon: icon,
|
|
);
|
|
}
|
|
|
|
/// 买入按钮 - 翡翠绿渐变
|
|
factory GradientButton.buy({
|
|
Key? key,
|
|
required String text,
|
|
VoidCallback? onPressed,
|
|
bool isLoading = false,
|
|
bool isFullWidth = true,
|
|
IconData? icon,
|
|
LinearGradient? gradient,
|
|
}) {
|
|
return GradientButton(
|
|
key: key,
|
|
text: text,
|
|
onPressed: onPressed,
|
|
isLoading: isLoading,
|
|
isFullWidth: isFullWidth,
|
|
icon: icon ?? Icons.arrow_downward_rounded,
|
|
);
|
|
}
|
|
|
|
/// 卖出按钮 - 红色渐变
|
|
factory GradientButton.sell({
|
|
Key? key,
|
|
required String text,
|
|
VoidCallback? onPressed,
|
|
bool isLoading = false,
|
|
bool isFullWidth = true,
|
|
IconData? icon,
|
|
LinearGradient? gradient,
|
|
}) {
|
|
return GradientButton(
|
|
key: key,
|
|
text: text,
|
|
onPressed: onPressed,
|
|
isLoading: isLoading,
|
|
isFullWidth: isFullWidth,
|
|
icon: icon ?? Icons.arrow_upward_rounded,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final appColors = context.appColors;
|
|
final colorScheme = context.colors;
|
|
final buttonGradient = gradient ?? appColors.ctaGradient;
|
|
|
|
// 主题感知颜色 - 在渐变背景上使用 onPrimary
|
|
final textColor = colorScheme.onPrimary;
|
|
|
|
return Container(
|
|
width: isFullWidth ? double.infinity : null,
|
|
height: height,
|
|
decoration: BoxDecoration(
|
|
gradient: buttonGradient,
|
|
borderRadius: BorderRadius.circular(AppRadius.xxl),
|
|
),
|
|
child: Material(
|
|
color: Colors.transparent,
|
|
child: InkWell(
|
|
onTap: isLoading ? null : onPressed,
|
|
borderRadius: BorderRadius.circular(AppRadius.xxl),
|
|
child: Center(
|
|
child: Row(
|
|
mainAxisSize: isFullWidth ? MainAxisSize.max : MainAxisSize.min,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
if (isLoading)
|
|
SizedBox(
|
|
width: 20,
|
|
height: 20,
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2,
|
|
color: textColor,
|
|
),
|
|
)
|
|
else ...[
|
|
if (icon != null) ...[
|
|
Icon(icon, size: 18, color: textColor),
|
|
SizedBox(width: AppSpacing.sm),
|
|
],
|
|
Text(
|
|
text,
|
|
style: TextStyle(
|
|
color: textColor,
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Ghost 按钮 - 次要操作
|
|
///
|
|
/// 设计规则:
|
|
/// - Ghost Border: 15% opacity outline-variant
|
|
/// - 圆角: xxl (24px)
|
|
/// - 主色文字
|
|
class GhostButton extends StatelessWidget {
|
|
final String text;
|
|
final VoidCallback? onPressed;
|
|
final bool isLoading;
|
|
final bool isFullWidth;
|
|
final IconData? icon;
|
|
|
|
const GhostButton({
|
|
super.key,
|
|
required this.text,
|
|
this.onPressed,
|
|
this.isLoading = false,
|
|
this.isFullWidth = true,
|
|
this.icon,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final textColor = context.colors.primary;
|
|
final borderColor = context.appColors.ghostBorder;
|
|
|
|
return Container(
|
|
width: isFullWidth ? double.infinity : null,
|
|
height: 48,
|
|
decoration: BoxDecoration(
|
|
color: Colors.transparent,
|
|
border: Border.all(color: borderColor, width: 1),
|
|
borderRadius: BorderRadius.circular(AppRadius.xxl),
|
|
),
|
|
child: Material(
|
|
color: Colors.transparent,
|
|
child: InkWell(
|
|
onTap: isLoading ? null : onPressed,
|
|
borderRadius: BorderRadius.circular(AppRadius.xxl),
|
|
child: Center(
|
|
child: Row(
|
|
mainAxisSize: isFullWidth ? MainAxisSize.max : MainAxisSize.min,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
if (isLoading)
|
|
SizedBox(
|
|
width: 20,
|
|
height: 20,
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2,
|
|
color: textColor,
|
|
),
|
|
)
|
|
else ...[
|
|
if (icon != null) ...[
|
|
Icon(icon, size: 18, color: textColor),
|
|
SizedBox(width: AppSpacing.sm),
|
|
],
|
|
Text(
|
|
text,
|
|
style: TextStyle(
|
|
color: textColor,
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|