Files
fitnote/lib/record.dart
2025-11-30 22:06:56 +08:00

569 lines
16 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:fitnote/modesl/health.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:getwidget/getwidget.dart';
import 'package:intl/intl.dart';
class RecordPage extends StatefulWidget {
const RecordPage({super.key});
@override
State<RecordPage> createState() => _RecordPageState();
}
class _RecordPageState extends State<RecordPage> {
// 格式化当前日期
String _formatCurrentDate() {
final now = DateTime.now();
// 格式2025年11月28日周五
return "${DateFormat('yyyy年MM月dd日').format(now)}${_getWeekday(now.weekday)}";
}
// 数字星期转中文
String _getWeekday(int weekday) {
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
return weekdays[weekday - 1];
}
// 记录项数据(图标、标题、颜色)
final List<RecordItem> recordItems = [
RecordItem(
icon: FontAwesomeIcons.weightScale,
title: '体重',
color: const Color(0xFFF59E0B), // 橙色
),
RecordItem(
icon: FontAwesomeIcons.personRunning,
title: '运动',
color: const Color(0xFF38BDF8), // 天空蓝
),
RecordItem(
icon: FontAwesomeIcons.moon,
title: '睡眠',
color: const Color(0xFF10B981), // 薄荷绿
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
// 顶部导航栏
_buildHeader(),
// 主要内容区(滚动)
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
children: [
// 本月目标进度卡片
_buildGoalProgressCard(),
const SizedBox(height: 24),
// 今日记录区
_buildTodayRecordSection(),
],
),
),
),
],
),
),
);
}
// 顶部导航栏
Widget _buildHeader() {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
color: Colors.white,
// boxShadow: const [
// BoxShadow(
// color: Color(0x0A000000),
// blurRadius: 4,
// offset: Offset(0, 2),
// ),
// ],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'早上好,用户',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF1E293B),
),
),
const SizedBox(height: 4),
Text(
'今天是 ${_formatCurrentDate()}',
style: const TextStyle(fontSize: 12, color: Color(0xFF64748B)),
),
],
),
Row(
children: [
// 通知按钮
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: const Color(0xFFF1F5F9),
borderRadius: BorderRadius.circular(20),
),
child: Icon(
FontAwesomeIcons.bell,
color: const Color(0xFF64748B),
size: 18,
),
),
// 用户头像
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: const Color(0xFFE0F2FE), // 主色浅背景
borderRadius: BorderRadius.circular(20),
),
child: const Center(
child: Text(
'U',
style: TextStyle(
color: Color(0xFF38BDF8),
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
),
],
),
],
),
);
}
Widget _buildCard({required Widget child}) {
return Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: const Color(0xFF38BDF8).withOpacity(0.08),
blurRadius: 25,
offset: const Offset(0, 10),
),
BoxShadow(
color: const Color(0xFF38BDF8).withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 8),
),
],
),
child: child,
);
}
// 本月目标进度卡片
Widget _buildGoalProgressCard() {
return _buildCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 卡片标题
Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: const Color(0xFFE0F2FE),
borderRadius: BorderRadius.circular(20),
),
child: const Icon(
FontAwesomeIcons.trophy,
color: Color(0xFF38BDF8),
size: 18,
),
),
SizedBox(width: 6),
const Text(
'本月目标进度',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF1E293B),
),
),
],
),
const SizedBox(height: 28),
// 目标体重
_buildProgressItem(
title: '目标体重',
current: '65.2',
target: '60',
unit: 'kg',
progress: 0.85,
color: const Color(0xFFF59E0B),
),
const SizedBox(height: 28),
// 运动总时长目标
_buildProgressItem(
title: '运动总时长',
current: '450',
target: '600',
unit: '分钟',
progress: 0.75,
color: const Color(0xFF38BDF8),
),
const SizedBox(height: 28),
// 日均睡眠目标
_buildProgressItem(
title: '日均睡眠',
current: '7.2',
target: '8',
unit: '小时',
progress: 0.9,
color: const Color(0xFF10B981),
),
],
),
);
}
// 单个进度项组件
Widget _buildProgressItem({
required String title,
required String current,
required String target,
required String unit,
required double progress,
required Color color,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题+进度数值
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xFF475569),
),
),
Text(
'$current/$target $unit',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: color,
),
),
],
),
const SizedBox(height: 8),
GFProgressBar(
animation: true,
lineHeight: 20,
percentage: progress,
progressBarColor: color,
child: Text(
'${progress * 100}%',
textAlign: TextAlign.end,
style: TextStyle(color: Colors.white),
),
),
],
);
}
Widget _buildCircleIcon({required IconData icon, required Color color}) {
return Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary.withAlpha(50),
borderRadius: BorderRadius.circular(20),
),
child: Icon(icon, color: Theme.of(context).colorScheme.primary, size: 18),
);
}
// 今日记录区
Widget _buildTodayRecordSection() {
return _buildCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 区域标题
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
_buildCircleIcon(
icon: FontAwesomeIcons.calendarCheck,
color: Color(0xFF10B981),
),
SizedBox(width: 6),
Text(
'今日记录',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary,
),
),
],
),
// 日期标签
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
decoration: BoxDecoration(
color: const Color(0xFFF1F5F9),
borderRadius: BorderRadius.circular(16),
),
child: Text(
DateFormat('MM月dd日').format(DateTime.now()),
style: const TextStyle(
fontSize: 12,
color: Color(0xFF64748B),
fontWeight: FontWeight.w500,
),
),
),
],
),
const SizedBox(height: 20),
// 记录卡片列表
ListView.separated(
// 禁用滚动(父布局已为 SingleChildScrollView
physics: const NeverScrollableScrollPhysics(),
// 固定高度3个item + 间距每个item高度≈72间距16总高度=72*3 + 16*2 = 248
shrinkWrap: true,
itemCount: recordItems.length,
separatorBuilder: (context, index) => SizedBox(height: 8),
itemBuilder: (context, index) {
final item = recordItems[index];
return _buildRecordListTile(item);
},
),
],
),
);
}
// 增强版记录卡片(显示具体记录内容)
Widget _buildRecordListTile(RecordItem item) {
// 模拟已记录数据(实际项目可替换为真实数据)
final healthRecord = Health(
id: 1,
sportProject: '羽毛球',
sleepDuration: 20,
weight: 72,
sleepStartTime: '2025-11-27 23:00',
sleepEndTime: '2025-11-28 24:00',
date: '2025-11-28',
);
final recordData = _getMockRecordData(item.title);
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [item.color.withAlpha(10), Colors.white.withAlpha(200)],
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(10),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
child: ListTile(
// 左侧图标
leading: Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: item.color.withAlpha(30),
borderRadius: BorderRadius.circular(24),
),
child: Icon(item.icon, color: item.color, size: 22),
),
// 标题+具体记录内容
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
// 主标题
Text(
item.title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: item.color,
),
),
const SizedBox(height: 4),
// 具体记录内容(根据类型显示不同布局)
_buildRecordContent(item.title, recordData),
],
),
// 右侧按钮(添加/编辑)
trailing: GestureDetector(
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'${recordData["hasData"] ? "编辑" : "添加"}${item.title}记录',
),
),
);
},
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: item.color.withAlpha(30),
borderRadius: BorderRadius.circular(20),
),
child: Icon(
recordData["hasData"]
? FontAwesomeIcons.pencil
: FontAwesomeIcons.plus,
color: item.color,
size: 18,
),
),
),
// 取消默认波纹效果
splashColor: Colors.transparent,
// 增加内边距,适配新增内容
contentPadding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 12,
),
),
);
}
// 模拟记录数据(实际项目替换为真实数据来源)
Map<String, dynamic> _getMockRecordData(String type) {
switch (type) {
case "体重":
return {
"hasData": false,
"weight": 65.2, // kg
"updateTime": "08:30",
};
case "运动":
return {
"hasData": true,
"sportType": "跑步",
"duration": 45, // 分钟
"distance": 5.2, // km
"updateTime": "18:45",
};
case "睡眠":
return {
"hasData": true,
"sleepTime": "23:15",
"wakeTime": "07:30",
"duration": "8小时15分钟",
"updateTime": "今天",
};
default:
return {"hasData": false};
}
}
// 根据类型构建不同的记录内容布局
Widget _buildRecordContent(String type, Map<String, dynamic> data) {
// 未记录状态
if (!data["hasData"]) {
return Text(
"尚未记录今日数据,点击添加",
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
);
}
// 已记录状态:根据类型显示不同内容
switch (type) {
case "体重":
return Row(
children: [
Text(
"${data["weight"]} kg",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.grey[800],
),
),
],
);
case "运动":
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"${data["sportType"]} · ${data["duration"]}分钟",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.grey[800],
),
),
],
);
case "睡眠":
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"入睡 ${data["sleepTime"]} · 起床 ${data["wakeTime"]} · ${data["duration"]}",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.grey[800],
),
),
],
);
default:
return const SizedBox.shrink();
}
}
}
// 记录项模型
class RecordItem {
final IconData icon;
final String title;
final Color color;
RecordItem({required this.icon, required this.title, required this.color});
}