import 'package:fitnote/models/health.dart'; import 'package:fitnote/provider/health_provider.dart'; import 'package:fitnote/service/health_service.dart'; import 'package:fitnote/utils/record_utils.dart'; import 'package:fitnote/widget/record/common.dart'; import 'package:fitnote/widget/record/record_form.dart'; import 'package:flutter/material.dart'; import 'package:flutter_common/widget/common_widget.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:getwidget/getwidget.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; class RecordDaily extends StatefulWidget { const RecordDaily({super.key}); @override State createState() => _RecordDailyState(); } class _RecordDailyState extends State { final HealthService service = HealthService(); HealthRecord _record = HealthRecord.getEmpty(''); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { final provider = context.read(); _record = service.getAllRecordByDate(provider.date); provider.initForm(HealthRecord.getEmpty(provider.date)); }); } @override Widget build(BuildContext context) { return CommonCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ buildCardTitle( context: context, title: '今日记录', icon: FontAwesomeIcons.calendarCheck, ), _buildTodayTag(), ], ), const SizedBox(height: 20), ListView.separated( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: RecordType.values.length, separatorBuilder: (context, index) => SizedBox(height: 8), itemBuilder: (context, index) { final recordType = RecordType.values[index]; return _buildRecordListTile(recordType); }, ), ], ), ); } Widget _buildTodayTag() { return 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, ), ), ); } Widget _buildRecordListTile(RecordType type) { return Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [type.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: type.color.withAlpha(30), borderRadius: BorderRadius.circular(24), ), child: Icon(type.icon, color: type.color, size: 22), ), title: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( type.title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: type.color, ), ), const SizedBox(height: 4), _buildRecordContent(type), ], ), trailing: GestureDetector( onTap: () => onTapRecord(type), child: Container( width: 40, height: 40, decoration: BoxDecoration( color: type.color.withAlpha(30), borderRadius: BorderRadius.circular(20), ), child: Icon( checkHasRecordValue(_record, type) ? FontAwesomeIcons.pencil : FontAwesomeIcons.plus, color: type.color, size: 18, ), ), ), splashColor: Colors.transparent, contentPadding: const EdgeInsets.symmetric( horizontal: 20, vertical: 12, ), ), ); } void onTapRecord(RecordType type) { final provider = context.read(); provider.isEditing = checkHasRecordValue(_record, type); provider.type = type; if (provider.isEditing) { switch (provider.type) { case RecordType.weight: provider.updateWeight(_record.weight); break; case RecordType.sport: provider.updateSportProject(_record.sportProject); provider.updateSportDuration(_record.sportDuration); break; case RecordType.sleep: provider.updateSleepStartTime(_record.sleepStartTime); provider.updateSleepEndTime(_record.sleepEndTime); break; } } else { switch (provider.type) { case RecordType.weight: provider.updateWeight(70); break; case RecordType.sport: provider.updateSportProject('跑步'); provider.updateSportDuration(30); break; case RecordType.sleep: provider.updateSleepStartTime(''); provider.updateSleepEndTime(''); break; } } showDialog( context: context, builder: (context) => Dialog( child: Padding( padding: EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, children: [RecordForm(type: type), _buildDialogButton()], ), ), ), ); } Widget _buildDialogButton() { final colors = Theme.of(context).colorScheme; return Row( children: [ Expanded( child: GFButton( onPressed: () { Navigator.of(context).pop(); _resetRecord(); }, color: colors.secondary, text: "取消", ), ), const SizedBox(width: 12), Expanded( child: GFButton( onPressed: () { Navigator.of(context).pop(); _saveRecord(); }, color: colors.primary, text: "确定", ), ), ], ); } void _resetRecord() { final provider = context.read(); if (!provider.isEditing) { switch (provider.type) { case RecordType.weight: provider.updateWeight(0); break; case RecordType.sport: provider.updateSportProject('跑步'); provider.updateSportDuration(0); break; case RecordType.sleep: provider.updateSleepStartTime(''); provider.updateSleepEndTime(''); break; } } } void _saveRecord() async { final provider = context.read(); await service.updateRecord(provider.formItem); setState(() { _record = service.getAllRecordByDate(provider.date); }); provider.updateLatestWeight(service.getLatestWeight()); provider.updateTotalSpot(service.getTotalSport()); provider.updateAvgSleep(service.getAvgSleep()); } Widget _buildRecordContent(RecordType type) { if (!checkHasRecordValue(_record, type)) { return Text( "尚未记录今日数据,点击添加", style: TextStyle(fontSize: 12, color: Colors.grey[500]), ); } late String title; switch (type) { case RecordType.weight: title = "${_record.weight} kg"; case RecordType.sport: title = "${_record.sportProject} · ${_record.sportDuration}分钟"; case RecordType.sleep: final startTime = _record.sleepStartTime; final endTime = _record.sleepEndTime; if (startTime.isNotEmpty && endTime.isNotEmpty) { final duration = calSleepDuration(startTime, endTime); title = "入睡 $startTime · 起床 $endTime · ${duration}"; } else if (startTime.isNotEmpty) { title = "入睡 $startTime"; } else if (endTime.isNotEmpty) { title = "起床 $endTime"; } } return Text( title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Colors.grey[800], ), ); } }