feat: 饮食记录逻辑重构 + 通知管理分隔线修复 + 多页面 UI 调整
- 饮食: 新增 DietCommentaryPolicy + diet_record_logic, 饮食记录逻辑抽取复用 - 通知管理: 分隔线改为仿通知中心样式, 跳过图标区域只留文字下方 - 侧边栏: 对话记录操作栏浮层修复 + 常用功能间距收紧 - 智能体: 欢迎卡片去 400ms 延迟 + 胶囊去阴影 - 后端: AI 会话仓库新增方法 + 饮食评论策略 + 健康记录规则调整 - 其他: api_client IP 适配 + 多页面 UI 微调 + 新增测试
This commit is contained in:
@@ -342,20 +342,24 @@ class _UnreadHint extends StatelessWidget {
|
||||
margin: const EdgeInsets.fromLTRB(0, 2, 0, 14),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 11),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFFFBEB),
|
||||
color: AppColors.notificationLight,
|
||||
borderRadius: AppRadius.mdBorder,
|
||||
border: Border.all(color: const Color(0xFFFDE68A)),
|
||||
border: Border.all(color: AppColors.notificationBorder),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(LucideIcons.bellRing, size: 18, color: Color(0xFFF97316)),
|
||||
const Icon(
|
||||
LucideIcons.bellRing,
|
||||
size: 18,
|
||||
color: AppColors.notification,
|
||||
),
|
||||
const SizedBox(width: 9),
|
||||
Text(
|
||||
'你有 $unreadCount 条未读消息',
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Color(0xFF92400E),
|
||||
color: AppColors.notification,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -370,23 +374,14 @@ class _SectionTitle extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _SectionShell(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
LucideIcons.calendarDays,
|
||||
size: 18,
|
||||
color: AppColors.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
child: Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textHint,
|
||||
letterSpacing: 0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -421,34 +416,29 @@ class _CollapsibleSectionTitle extends StatelessWidget {
|
||||
child: _SectionShell(
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
LucideIcons.history,
|
||||
size: 18,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'$text · $count',
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textHint,
|
||||
letterSpacing: 0,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Text(
|
||||
expanded ? '收起' : '展开',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textHint,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const SizedBox(width: 4),
|
||||
Icon(
|
||||
expanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
|
||||
size: 22,
|
||||
color: AppColors.textSecondary,
|
||||
size: 18,
|
||||
color: AppColors.textHint,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -483,50 +473,17 @@ class _NotificationRow extends StatelessWidget {
|
||||
padding: const EdgeInsets.fromLTRB(14, 13, 12, 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
visual.color.withValues(alpha: 0.18),
|
||||
visual.lightColor,
|
||||
],
|
||||
),
|
||||
borderRadius: AppRadius.mdBorder,
|
||||
border: Border.all(
|
||||
color: visual.color.withValues(alpha: 0.22),
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
visual.icon,
|
||||
size: 24,
|
||||
color: visual.color,
|
||||
),
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
gradient: visual.gradient,
|
||||
borderRadius: AppRadius.mdBorder,
|
||||
border: Border.all(
|
||||
color: visual.borderColor.withValues(alpha: 0.85),
|
||||
),
|
||||
if (!item.isRead)
|
||||
Positioned(
|
||||
top: -2,
|
||||
right: -2,
|
||||
child: Container(
|
||||
width: 10,
|
||||
height: 10,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.error,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: Colors.white,
|
||||
width: 1.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Icon(visual.icon, size: 24, color: Colors.white),
|
||||
),
|
||||
const SizedBox(width: 13),
|
||||
Expanded(
|
||||
@@ -594,14 +551,22 @@ class _NotificationRow extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
if (item.actionType != null) ...[
|
||||
const SizedBox(width: 6),
|
||||
const Icon(
|
||||
Icons.chevron_right_rounded,
|
||||
size: 22,
|
||||
color: AppColors.textSecondary,
|
||||
const SizedBox(width: 10),
|
||||
SizedBox(
|
||||
width: 12,
|
||||
child: Center(
|
||||
child: item.isRead
|
||||
? const SizedBox.shrink()
|
||||
: Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.error,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -641,21 +606,33 @@ class _NotificationVisual {
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
final Color lightColor;
|
||||
final Color borderColor;
|
||||
final LinearGradient gradient;
|
||||
final String label;
|
||||
|
||||
const _NotificationVisual(this.icon, this.color, this.lightColor, this.label);
|
||||
const _NotificationVisual(
|
||||
this.icon,
|
||||
this.color,
|
||||
this.lightColor,
|
||||
this.borderColor,
|
||||
this.gradient,
|
||||
this.label,
|
||||
);
|
||||
|
||||
factory _NotificationVisual.fromModule(AppModuleVisual visual) {
|
||||
return _NotificationVisual(
|
||||
visual.icon,
|
||||
visual.color,
|
||||
visual.lightColor,
|
||||
visual.borderColor,
|
||||
visual.gradient,
|
||||
visual.label,
|
||||
);
|
||||
}
|
||||
|
||||
factory _NotificationVisual.of(InAppNotification item) {
|
||||
switch (item.actionType) {
|
||||
final kind = item.actionType ?? item.type;
|
||||
switch (kind) {
|
||||
case 'exercise':
|
||||
return _NotificationVisual.fromModule(AppModuleVisuals.exercise);
|
||||
case 'health':
|
||||
@@ -664,6 +641,12 @@ class _NotificationVisual {
|
||||
LucideIcons.triangleAlert,
|
||||
Color(0xFFEF4444),
|
||||
Color(0xFFFEE2E2),
|
||||
Color(0xFFFECACA),
|
||||
LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Color(0xFFFF7A7A), Color(0xFFEF4444)],
|
||||
),
|
||||
'紧急',
|
||||
)
|
||||
: _NotificationVisual.fromModule(AppModuleVisuals.health);
|
||||
@@ -673,11 +656,21 @@ class _NotificationVisual {
|
||||
LucideIcons.fileWarning,
|
||||
Color(0xFFEF4444),
|
||||
Color(0xFFFEE2E2),
|
||||
Color(0xFFFECACA),
|
||||
LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Color(0xFFFF7A7A), Color(0xFFEF4444)],
|
||||
),
|
||||
'报告',
|
||||
)
|
||||
: _NotificationVisual.fromModule(AppModuleVisuals.report);
|
||||
default:
|
||||
case 'medication':
|
||||
return _NotificationVisual.fromModule(AppModuleVisuals.medication);
|
||||
case 'diet':
|
||||
return _NotificationVisual.fromModule(AppModuleVisuals.diet);
|
||||
default:
|
||||
return _NotificationVisual.fromModule(AppModuleVisuals.notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user