feat: UI 清新风全面改造 — 朝露主题 + shadcn_ui + 全局字号放大

- 全新"朝露"主题:深青绿主色(#2D6A4F),暖白底,完整设计Token
- 引入 shadcn_ui 组件库,MaterialApp 注入 ShadTheme
- 新增 4 个公共组件:AppCard、AppMenuItem、AppEmptyState、AppTabChip
- 全面消除硬编码颜色,统一使用 AppTheme Token
- 全局字号 +3~4pt,图标等比放大 +3px
- home/medication/profile/settings/login 等核心页面重写
- 路由和功能逻辑零改动
This commit is contained in:
MingNian
2026-06-08 18:06:18 +08:00
parent 16d1d3d305
commit 58af5f6d5b
28 changed files with 1616 additions and 812 deletions

View File

@@ -351,9 +351,9 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
: null,
),
child: Column(mainAxisSize: MainAxisSize.min, children: [
Icon(m.icon, size: 20, color: isSelected ? Colors.white : _kSubText),
Icon(m.icon, size: 23, color: isSelected ? Colors.white : _kSubText),
const SizedBox(height: 4),
Text(m.label, style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: isSelected ? Colors.white : _kSubText)),
Text(m.label, style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: isSelected ? Colors.white : _kSubText)),
]),
),
),
@@ -376,15 +376,15 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
alignment: Alignment.center,
children: [
const CircularProgressIndicator(strokeWidth: 3, color: _kPrimary),
const Icon(Icons.restaurant, size: 22, color: _kPrimary),
const Icon(Icons.restaurant, size: 25, color: _kPrimary),
],
),
),
const SizedBox(height: 20),
const Text('正在识别食物...', style: TextStyle(fontSize: 15, color: _kSubText)),
const Text('正在识别食物...', style: TextStyle(fontSize: 18, color: _kSubText)),
if (state.errorMessage != null) ...[
const SizedBox(height: 8),
Text(state.errorMessage!, style: const TextStyle(fontSize: 13, color: AppTheme.error), textAlign: TextAlign.center),
Text(state.errorMessage!, style: const TextStyle(fontSize: 16, color: AppTheme.error), textAlign: TextAlign.center),
],
]),
),
@@ -411,16 +411,16 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(color: _kPrimaryLight, borderRadius: BorderRadius.circular(8)),
child: const Text('识别结果', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: _kPrimary)),
child: const Text('识别结果', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: _kPrimary)),
),
const Spacer(),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(color: const Color(0xFFFFF8EE), borderRadius: BorderRadius.circular(8)),
child: Text('$totalCal kcal', style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: _kWarning)),
child: Text('$totalCal kcal', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: _kWarning)),
),
IconButton(
icon: const Icon(Icons.add_circle_outline, size: 22, color: _kPrimary),
icon: const Icon(Icons.add_circle_outline, size: 25, color: _kPrimary),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
onPressed: () => ref.read(dietProvider.notifier).addFood(),
@@ -457,7 +457,7 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
color: food.selected ? _kPrimary : Colors.white,
border: Border.all(color: food.selected ? _kPrimary : const Color(0xFFCCCCCC), width: 2),
),
child: food.selected ? const Icon(Icons.check, size: 14, color: Colors.white) : null,
child: food.selected ? const Icon(Icons.check, size: 17, color: Colors.white) : null,
),
),
const SizedBox(width: 12),
@@ -466,7 +466,7 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
TextField(
controller: TextEditingController(text: food.name),
onChanged: (v) => ref.read(dietProvider.notifier).updateFoodName(food.id, v),
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: _kText),
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: _kText),
decoration: const InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
@@ -480,13 +480,13 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
child: TextField(
controller: TextEditingController(text: food.portion),
onChanged: (v) => ref.read(dietProvider.notifier).updateFoodPortion(food.id, v),
style: const TextStyle(fontSize: 12, color: _kSubText),
style: const TextStyle(fontSize: 15, color: _kSubText),
decoration: const InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
hintText: '份量',
hintStyle: TextStyle(fontSize: 12, color: AppTheme.textHint),
hintStyle: TextStyle(fontSize: 15, color: AppTheme.textHint),
),
),
),
@@ -497,24 +497,24 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
controller: TextEditingController(text: food.calories.toString()),
onChanged: (v) => ref.read(dietProvider.notifier).updateFoodCalories(food.id, int.tryParse(v) ?? 0),
keyboardType: TextInputType.number,
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: _kWarning),
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: _kWarning),
textAlign: TextAlign.right,
decoration: const InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
border: InputBorder.none,
hintText: '0',
hintStyle: TextStyle(fontSize: 12),
hintStyle: TextStyle(fontSize: 15),
),
),
),
const SizedBox(width: 2),
const Text('kcal', style: TextStyle(fontSize: 11, color: _kSubText)),
const Text('kcal', style: TextStyle(fontSize: 14, color: _kSubText)),
]),
]),
),
IconButton(
icon: const Icon(Icons.close, size: 16, color: Color(0xFFBBBBBB)),
icon: const Icon(Icons.close, size: 19, color: Color(0xFFBBBBBB)),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
onPressed: () => ref.read(dietProvider.notifier).removeFood(food.id),
@@ -552,8 +552,8 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
),
),
Column(mainAxisSize: MainAxisSize.min, children: [
Text('$totalCalories', style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w800, color: Colors.white)),
Text('kcal', style: const TextStyle(fontSize: 10, color: Colors.white70)),
Text('$totalCalories', style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w800, color: Colors.white)),
Text('kcal', style: const TextStyle(fontSize: 13, color: Colors.white70)),
]),
],
),
@@ -561,7 +561,7 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
const SizedBox(width: 16),
Expanded(
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
const Text('本餐热量', style: TextStyle(fontSize: 14, color: Colors.white70)),
const Text('本餐热量', style: TextStyle(fontSize: 17, color: Colors.white70)),
const SizedBox(height: 4),
Row(children: [
Expanded(child: _macroBar('碳水', 0.55, const Color(0xFFFFF9C4))),
@@ -582,7 +582,7 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
Row(children: [
Container(width: 6, height: 6, decoration: BoxDecoration(color: color, shape: BoxShape.circle)),
const SizedBox(width: 4),
Text(label, style: const TextStyle(fontSize: 10, color: Colors.white70)),
Text(label, style: const TextStyle(fontSize: 13, color: Colors.white70)),
]),
const SizedBox(height: 3),
ClipRRect(
@@ -607,10 +607,10 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
Container(
width: 32, height: 32,
decoration: BoxDecoration(color: _kPrimaryLight, borderRadius: BorderRadius.circular(8)),
child: const Icon(Icons.auto_awesome, size: 16, color: _kPrimary),
child: const Icon(Icons.auto_awesome, size: 19, color: _kPrimary),
),
const SizedBox(width: 10),
Expanded(child: Text(text, style: const TextStyle(fontSize: 13, color: _kText, height: 1.6))),
Expanded(child: Text(text, style: const TextStyle(fontSize: 16, color: _kText, height: 1.6))),
]),
),
);
@@ -650,11 +650,11 @@ class _DietCapturePageState extends ConsumerState<DietCapturePage> {
backgroundColor: _kPrimary,
foregroundColor: Colors.white,
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(AppTheme.radiusMd)),
textStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(AppTheme.rMd)),
textStyle: const TextStyle(fontSize: 19, fontWeight: FontWeight.w600),
),
child: const Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Icon(Icons.check_circle_outline, size: 20),
Icon(Icons.check_circle_outline, size: 23),
SizedBox(width: 8),
Text('保存记录'),
]),