Files
AI-Health/health_app/lib/core/app_theme.dart
MingNian f01fc9268d feat: UI清爽紫蓝风全面改造 + 对话卡片重构 + 配色体系升级
- 新增 AppColors 统一配色方案(清爽紫蓝,参考蚂蚁阿福风格)
- 新增 common_widgets(GradientBorderButton / CardActionButton / IconBox)
- AgentWelcomeCard 美化:渐变 header + AI标签 + 核心功能区 + 快捷操作区
- DataConfirmCard 统一:三合一(健康/药品/运动),可编辑字段列表
- 删除死代码:medicationConfirm/dietAnalysis/reportAnalysis/quickOptions 卡片
- 删除死路由:doctors/profileEdit/editProfile
- AI 对话去除 Markdown 符号(_stripMd),统一行间距 1.5
- 逐字淡入动画修复:key 改用 stableId 避免重复触发
- 健康概览时间修复:前端发送 UTC 避免时区歧义
- PG 数据目录迁入项目 backend/pgdata/,加入 .gitignore
- 新增欧姆龙血压计实施方案文档
2026-06-09 17:04:11 +08:00

161 lines
6.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'app_colors.dart';
/// 健康管家 — 清爽紫蓝风
class AppTheme {
AppTheme._();
// ── 主色调 ──
static const Color primary = AppColors.primaryPurple;
static const Color primaryLight = AppColors.iconBackground;
static const Color primaryDark = AppColors.iconColor;
static const Color primaryGlow = AppColors.purpleGradientStart;
// ── 中性色 ──
static const Color bg = AppColors.backgroundSecondary;
static const Color surface = AppColors.cardBackground;
static const Color text = AppColors.textPrimary;
static const Color textSub = AppColors.textSecondary;
static const Color textHint = AppColors.textHint;
static const Color border = AppColors.border;
static const Color divider = AppColors.borderLight;
// ── 语义色 ──
static const Color success = AppColors.success;
static const Color error = AppColors.error;
static const Color warning = AppColors.warning;
static const Color accent = AppColors.primaryBlue;
static const Color info = AppColors.primaryBlue;
// ── 圆角 ──
static const double rXs = 6;
static const double rSm = 10;
static const double rMd = 14;
static const double rLg = 20;
static const double rXl = 28;
static const double rPill = 999;
// ── 间距 ──
static const double sXs = 4;
static const double sSm = 8;
static const double sMd = 12;
static const double sLg = 16;
static const double sXl = 20;
static const double sXxl = 28;
// ── 阴影 ──
static BoxShadow get shadowCard =>
BoxShadow(color: primary.withAlpha(14), blurRadius: 20, offset: const Offset(0, 4));
static BoxShadow get shadowLight =>
BoxShadow(color: primary.withAlpha(8), blurRadius: 12, offset: const Offset(0, 2));
static BoxShadow get shadowElevated =>
BoxShadow(color: primary.withAlpha(20), blurRadius: 30, offset: const Offset(0, 8));
// ── 智能体配色 ──
static const Map<String, Color> agentColors = {
'default': AppColors.iconBackground,
'consultation': Color(0xFFE0F0FF),
'health': Color(0xFFE8FFE8),
'diet': Color(0xFFFFF0E0),
'medication': Color(0xFFFFE8EC),
'report': Color(0xFFE8F0FF),
'exercise': Color(0xFFF0E8FF),
};
static Color agentLight(String? name) => agentColors[name] ?? primaryLight;
// ── Material 主题 ──
static ThemeData get lightTheme => ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: primary,
primary: primary,
surface: bg,
brightness: Brightness.light,
),
scaffoldBackgroundColor: bg,
fontFamily: null,
appBarTheme: const AppBarTheme(
backgroundColor: surface,
foregroundColor: text,
elevation: 0,
centerTitle: true,
scrolledUnderElevation: 0,
titleTextStyle: TextStyle(fontSize: 23, fontWeight: FontWeight.w600, color: text),
),
cardTheme: CardThemeData(
color: surface,
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(rLg)),
margin: EdgeInsets.zero,
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: bg,
contentPadding: const EdgeInsets.symmetric(horizontal: sLg, vertical: 16),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(rMd), borderSide: BorderSide.none),
enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(rMd), borderSide: BorderSide.none),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(rMd),
borderSide: const BorderSide(color: primary, width: 2),
),
hintStyle: const TextStyle(color: textHint, fontSize: 20),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: primary,
foregroundColor: Colors.white,
minimumSize: const Size(double.infinity, 56),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(rPill)),
textStyle: const TextStyle(fontSize: 21, fontWeight: FontWeight.w600),
elevation: 0,
),
),
dialogTheme: DialogThemeData(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(rXl))),
textTheme: const TextTheme(
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.w700, color: text, letterSpacing: -0.5),
titleLarge: TextStyle(fontSize: 23, fontWeight: FontWeight.w600, color: text),
titleMedium: TextStyle(fontSize: 21, fontWeight: FontWeight.w600, color: text),
bodyLarge: TextStyle(fontSize: 21, color: text, height: 1.5),
bodyMedium: TextStyle(fontSize: 20, color: textSub, height: 1.4),
labelMedium: TextStyle(fontSize: 18, color: textSub),
labelSmall: TextStyle(fontSize: 16, color: textHint),
),
);
// ── Shadcn UI 主题 ──
static ShadThemeData get shadTheme => ShadThemeData(
brightness: Brightness.light,
colorScheme: const ShadVioletColorScheme.light(
background: bg,
foreground: text,
card: surface,
cardForeground: text,
popover: surface,
popoverForeground: text,
primary: primary,
primaryForeground: Colors.white,
secondary: divider,
secondaryForeground: text,
muted: divider,
mutedForeground: textSub,
accent: accent,
accentForeground: Colors.white,
destructive: error,
destructiveForeground: Colors.white,
border: border,
input: border,
ring: primary,
selection: primaryGlow,
),
radius: BorderRadius.circular(rMd),
);
}