feat:更新历史记录模块

This commit is contained in:
2025-12-02 20:00:34 +08:00
parent 62108248aa
commit b3bb3378c3
6 changed files with 50 additions and 66 deletions

View File

@@ -9,7 +9,7 @@ part 'health.g.dart';
@HiveType(typeId: 0) @HiveType(typeId: 0)
class HealthRecord extends HiveObject { class HealthRecord extends HiveObject {
@HiveField(0) @HiveField(0)
int id; String date;
@HiveField(1) @HiveField(1)
String sportProject; String sportProject;
@@ -26,11 +26,7 @@ class HealthRecord extends HiveObject {
@HiveField(5) @HiveField(5)
String sleepEndTime; String sleepEndTime;
@HiveField(7)
String date;
HealthRecord({ HealthRecord({
required this.id,
required this.sportProject, required this.sportProject,
required this.sportDuration, required this.sportDuration,
required this.weight, required this.weight,
@@ -41,7 +37,6 @@ class HealthRecord extends HiveObject {
static HealthRecord getEmpty(DateTime date) { static HealthRecord getEmpty(DateTime date) {
return HealthRecord( return HealthRecord(
id: DateTime.now().millisecondsSinceEpoch ~/ 1000,
sportProject: '', sportProject: '',
sportDuration: 0, sportDuration: 0,
weight: 0, weight: 0,
@@ -61,13 +56,12 @@ class HealthRecord extends HiveObject {
String? date, String? date,
}) { }) {
return HealthRecord( return HealthRecord(
id: id ?? this.id,
date: date ?? this.date, date: date ?? this.date,
weight: weight ?? this.weight, weight: weight ?? this.weight,
sportProject: sportProject ?? this.sportProject, sportProject: sportProject ?? this.sportProject,
sportDuration: sportDuration ?? this.sportDuration, sportDuration: sportDuration ?? this.sportDuration,
sleepStartTime: sleepStartTime ?? this.sleepStartTime, sleepStartTime: sleepStartTime ?? this.sleepStartTime,
sleepEndTime: sleepEndTime ?? this.sleepEndTime sleepEndTime: sleepEndTime ?? this.sleepEndTime,
); );
} }
} }

View File

@@ -17,22 +17,21 @@ class HealthRecordAdapter extends TypeAdapter<HealthRecord> {
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
}; };
return HealthRecord( return HealthRecord(
id: fields[0] as int,
sportProject: fields[1] as String, sportProject: fields[1] as String,
sportDuration: fields[2] as num, sportDuration: fields[2] as num,
weight: fields[3] as num, weight: fields[3] as num,
sleepStartTime: fields[4] as String, sleepStartTime: fields[4] as String,
sleepEndTime: fields[5] as String, sleepEndTime: fields[5] as String,
date: fields[7] as String, date: fields[0] as String,
); );
} }
@override @override
void write(BinaryWriter writer, HealthRecord obj) { void write(BinaryWriter writer, HealthRecord obj) {
writer writer
..writeByte(7) ..writeByte(6)
..writeByte(0) ..writeByte(0)
..write(obj.id) ..write(obj.date)
..writeByte(1) ..writeByte(1)
..write(obj.sportProject) ..write(obj.sportProject)
..writeByte(2) ..writeByte(2)
@@ -42,9 +41,7 @@ class HealthRecordAdapter extends TypeAdapter<HealthRecord> {
..writeByte(4) ..writeByte(4)
..write(obj.sleepStartTime) ..write(obj.sleepStartTime)
..writeByte(5) ..writeByte(5)
..write(obj.sleepEndTime) ..write(obj.sleepEndTime);
..writeByte(7)
..write(obj.date);
} }
@override @override

View File

@@ -32,30 +32,10 @@ class _HistoryPageState extends State<HistoryPage> {
selectedDayPredicate: (day) => isSameDay(provider.selectedDate, day), selectedDayPredicate: (day) => isSameDay(provider.selectedDate, day),
onDaySelected: (selectedDay, focusedDay) { onDaySelected: (selectedDay, focusedDay) {
if (!isSameDay(provider.selectedDate, selectedDay)) { if (!isSameDay(provider.selectedDate, selectedDay)) {
setState(() { provider.updateSelectDate(selectedDay);
provider.selectedDate = selectedDay; provider.updateRecord(service.getRecordByDate(provider.selectedDate));
provider.focusedDate = focusedDay; }
// provider.updateRecord(service.getRecordByDate(provider.selectedDate));
// provider.refreshSelectRecord();
});
} }
},
onPageChanged: (focusedDay) {
provider.focusedDate = focusedDay;
// provider.refreshRecordList();
},
// 自定义日期单元格构建器
// calendarBuilders: CalendarBuilders(
// defaultBuilder:
// (context, day, focusedDay) =>
// _buildDateItem(day, false, false, provider),
// selectedBuilder:
// (context, day, focusedDay) =>
// _buildDateItem(day, true, false, provider),
// todayBuilder:
// (context, day, focusedDay) =>
// _buildDateItem(day, false, true, provider),
// ),
); );
} }

View File

@@ -1,11 +1,10 @@
import 'package:fitnote/models/health.dart'; import 'package:fitnote/models/health.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_common/flutter_common.dart';
class HealthProvider with ChangeNotifier { class HealthProvider with ChangeNotifier {
late HealthRecord formItem; HealthRecord formItem = HealthRecord.getEmpty(DateTime.now());
HealthRecord currentRecord = HealthRecord.getEmpty(DateTime.now());
DateTime selectedDate = DateTime.now(); DateTime selectedDate = DateTime.now();
DateTime focusedDate = DateTime.now();
RecordType type = RecordType.weight; RecordType type = RecordType.weight;
bool isEditing = false; bool isEditing = false;
@@ -18,6 +17,16 @@ class HealthProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void updateRecord(HealthRecord record) {
currentRecord = record;
notifyListeners();
}
void updateSelectDate(DateTime date) {
selectedDate = date;
notifyListeners();
}
void updateWeight(num weight) { void updateWeight(num weight) {
formItem.weight = weight; formItem.weight = weight;
notifyListeners(); notifyListeners();

View File

@@ -93,17 +93,18 @@ class HealthService {
Future<bool> updateRecord(HealthRecord record) async { Future<bool> updateRecord(HealthRecord record) async {
try { try {
List<HealthRecord> records = print(record.date);
final existingRecords =
box.values.where((item) => item.date == record.date).toList(); box.values.where((item) => item.date == record.date).toList();
if (records.isEmpty) { if (existingRecords.isEmpty) {
await addRecord(record); await addRecord(record);
} else { } else {
await record.save(); await record.save();
} }
return true; return true;
} catch (e) { } catch (e) {
print(e.toString());
return false; return false;
} }
} }

View File

@@ -5,6 +5,7 @@ import 'package:fitnote/utils/record_utils.dart';
import 'package:fitnote/widget/record/common.dart'; import 'package:fitnote/widget/record/common.dart';
import 'package:fitnote/widget/record/record_form.dart'; import 'package:fitnote/widget/record/record_form.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_common/flutter_common.dart';
import 'package:flutter_common/widget/common_widget.dart'; import 'package:flutter_common/widget/common_widget.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:getwidget/getwidget.dart'; import 'package:getwidget/getwidget.dart';
@@ -21,16 +22,13 @@ class RecordDaily extends StatefulWidget {
class _RecordDailyState extends State<RecordDaily> { class _RecordDailyState extends State<RecordDaily> {
final HealthService service = HealthService(); final HealthService service = HealthService();
HealthRecord _record = HealthRecord.getEmpty(DateTime.now());
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
final provider = context.read<HealthProvider>(); final provider = context.read<HealthProvider>();
_record = service.getRecordByDate(provider.selectedDate); provider.currentRecord = service.getRecordByDate(provider.selectedDate);
provider.initForm(HealthRecord.getEmpty(provider.selectedDate));
}); });
} }
@@ -68,6 +66,8 @@ class _RecordDailyState extends State<RecordDaily> {
} }
Widget _buildTodayTag() { Widget _buildTodayTag() {
final provider = context.watch<HealthProvider>();
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -75,7 +75,7 @@ class _RecordDailyState extends State<RecordDaily> {
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
), ),
child: Text( child: Text(
DateFormat('MM月dd日').format(DateTime.now()), DateFormat('MM月dd日').format(provider.selectedDate),
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
color: Color(0xFF64748B), color: Color(0xFF64748B),
@@ -86,6 +86,8 @@ class _RecordDailyState extends State<RecordDaily> {
} }
Widget _buildRecordListTile(RecordType type) { Widget _buildRecordListTile(RecordType type) {
final provider = context.watch<HealthProvider>();
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
@@ -125,7 +127,7 @@ class _RecordDailyState extends State<RecordDaily> {
), ),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
_buildRecordContent(type), _buildRecordContent(provider.currentRecord, type),
], ],
), ),
trailing: GestureDetector( trailing: GestureDetector(
@@ -138,7 +140,7 @@ class _RecordDailyState extends State<RecordDaily> {
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
child: Icon( child: Icon(
checkHasRecordValue(_record, type) checkHasRecordValue(provider.currentRecord, type)
? FontAwesomeIcons.pencil ? FontAwesomeIcons.pencil
: FontAwesomeIcons.plus, : FontAwesomeIcons.plus,
color: type.color, color: type.color,
@@ -157,21 +159,23 @@ class _RecordDailyState extends State<RecordDaily> {
void onTapRecord(RecordType type) { void onTapRecord(RecordType type) {
final provider = context.read<HealthProvider>(); final provider = context.read<HealthProvider>();
provider.isEditing = checkHasRecordValue(_record, type); final record = provider.currentRecord;
provider.isEditing = checkHasRecordValue(record, type);
provider.type = type; provider.type = type;
if (provider.isEditing) { if (provider.isEditing) {
switch (provider.type) { switch (provider.type) {
case RecordType.weight: case RecordType.weight:
provider.updateWeight(_record.weight); provider.updateWeight(record.weight);
break; break;
case RecordType.sport: case RecordType.sport:
provider.updateSportProject(_record.sportProject); provider.updateSportProject(record.sportProject);
provider.updateSportDuration(_record.sportDuration); provider.updateSportDuration(record.sportDuration);
break; break;
case RecordType.sleep: case RecordType.sleep:
provider.updateSleepStartTime(_record.sleepStartTime); provider.updateSleepStartTime(record.sleepStartTime);
provider.updateSleepEndTime(_record.sleepEndTime); provider.updateSleepEndTime(record.sleepEndTime);
break; break;
} }
} else { } else {
@@ -256,19 +260,18 @@ class _RecordDailyState extends State<RecordDaily> {
void _saveRecord() async { void _saveRecord() async {
final provider = context.read<HealthProvider>(); final provider = context.read<HealthProvider>();
provider.formItem.date = formatDate(provider.selectedDate);
await service.updateRecord(provider.formItem); await service.updateRecord(provider.formItem);
setState(() { provider.updateRecord(service.getRecordByDate(provider.selectedDate));
_record = service.getRecordByDate(provider.selectedDate);
});
provider.updateLatestWeight(service.getLatestWeight()); provider.updateLatestWeight(service.getLatestWeight());
provider.updateTotalSpot(service.getTotalSport()); provider.updateTotalSpot(service.getTotalSport());
provider.updateAvgSleep(service.getAvgSleep()); provider.updateAvgSleep(service.getAvgSleep());
} }
Widget _buildRecordContent(RecordType type) { Widget _buildRecordContent(HealthRecord record, RecordType type) {
if (!checkHasRecordValue(_record, type)) { if (!checkHasRecordValue(record, type)) {
return Text( return Text(
"尚未记录今日数据,点击添加", "尚未记录今日数据,点击添加",
style: TextStyle(fontSize: 12, color: Colors.grey[500]), style: TextStyle(fontSize: 12, color: Colors.grey[500]),
@@ -278,12 +281,12 @@ class _RecordDailyState extends State<RecordDaily> {
late String title; late String title;
switch (type) { switch (type) {
case RecordType.weight: case RecordType.weight:
title = "${_record.weight} kg"; title = "${record.weight} kg";
case RecordType.sport: case RecordType.sport:
title = "${_record.sportProject} · ${_record.sportDuration}分钟"; title = "${record.sportProject} · ${record.sportDuration}分钟";
case RecordType.sleep: case RecordType.sleep:
final startTime = _record.sleepStartTime; final startTime = record.sleepStartTime;
final endTime = _record.sleepEndTime; final endTime = record.sleepEndTime;
if (startTime.isNotEmpty && endTime.isNotEmpty) { if (startTime.isNotEmpty && endTime.isNotEmpty) {
final duration = calSleepDuration(startTime, endTime); final duration = calSleepDuration(startTime, endTime);
title = "入睡 $startTime · 起床 $endTime · ${duration}"; title = "入睡 $startTime · 起床 $endTime · ${duration}";