import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:image_picker/image_picker.dart'; import 'package:file_picker/file_picker.dart'; import '../../core/api_client.dart'; import '../../core/navigation_provider.dart'; import '../../providers/auth_provider.dart'; import '../../providers/chat_provider.dart'; import '../../widgets/agent_bar.dart'; import '../../widgets/health_drawer.dart'; import 'widgets/chat_messages_view.dart'; /// 首页——主界面 class HomePage extends ConsumerStatefulWidget { const HomePage({super.key}); @override ConsumerState createState() => _HomePageState(); } class _HomePageState extends ConsumerState { final _textCtrl = TextEditingController(); final _scrollCtrl = ScrollController(); bool _taskCardsExpanded = true; @override void dispose() { _textCtrl.dispose(); _scrollCtrl.dispose(); super.dispose(); } void _sendMessage() { final text = _textCtrl.text.trim(); if (text.isEmpty) return; _textCtrl.clear(); ref.read(chatProvider.notifier).sendMessage(text); } @override Widget build(BuildContext context) { final chatState = ref.watch(chatProvider); final selectedAgent = ref.watch(selectedAgentProvider); return Scaffold( drawer: const HealthDrawer(), body: SafeArea( child: Column(children: [ _buildHeader(context), if (_taskCardsExpanded) _buildTaskCards(chatState), Expanded(child: ChatMessagesView(scrollCtrl: _scrollCtrl, messages: chatState.messages)), if (selectedAgent != null) _buildAgentPanel(context, selectedAgent), const AgentBar(), _buildInputBar(), ]), ), ); } Widget _buildHeader(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row(children: [ Builder(builder: (ctx) => IconButton( icon: const Icon(Icons.menu, size: 24), onPressed: () => Scaffold.of(ctx).openDrawer(), )), const Spacer(), Text('健康管家', style: Theme.of(context).textTheme.titleLarge), const Spacer(), const SizedBox(width: 48), ]), ); } Widget _buildTaskCards(ChatState chatState) { return GestureDetector( onVerticalDragUpdate: (d) { if (d.delta.dy < -10) setState(() => _taskCardsExpanded = false); }, child: Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFFEDEBFF), borderRadius: BorderRadius.circular(12), ), child: Column(children: [ Row(children: [ const Icon(Icons.wb_sunny, size: 18, color: Color(0xFF635BFF)), const SizedBox(width: 8), const Text('早上好!', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600)), const Spacer(), GestureDetector( onTap: () => setState(() => _taskCardsExpanded = false), child: const Icon(Icons.keyboard_arrow_up, size: 20, color: Color(0xFF666666)), ), ]), if (chatState.noticeText != null) Padding( padding: const EdgeInsets.only(top: 8), child: Text(chatState.noticeText!, style: const TextStyle(fontSize: 14, color: Color(0xFF666666))), ), ]), ), ); } Widget _buildAgentPanel(BuildContext context, ActiveAgent agent) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: const BorderRadius.vertical(top: Radius.circular(16)), boxShadow: [BoxShadow(color: const Color(0xFF635BFF).withAlpha(20), blurRadius: 8, offset: const Offset(0, -2))], ), child: Column(mainAxisSize: MainAxisSize.min, children: _getAgentButtons(agent)), ); } List _getAgentButtons(ActiveAgent agent) { final buttons = []; if (agent == ActiveAgent.health) { buttons.add(_panelBtn('手动录入血压', Icons.favorite)); buttons.add(_panelBtn('手动录入血糖', Icons.bloodtype)); buttons.add(_panelBtn('手动录入心率', Icons.monitor_heart)); } else if (agent == ActiveAgent.diet) { buttons.add(_panelBtn('拍照', Icons.camera_alt)); buttons.add(_panelBtn('上传照片', Icons.photo_library)); } else if (agent == ActiveAgent.medication) { buttons.add(_panelBtn('用药管理', Icons.medication)); buttons.add(_panelBtn('用药提醒', Icons.alarm)); } else if (agent == ActiveAgent.consultation) { buttons.add(_panelBtn('找医生', Icons.person_search)); } else if (agent == ActiveAgent.exercise) { buttons.add(_panelBtn('查看本周计划', Icons.calendar_view_week)); buttons.add(_panelBtn('创建新计划', Icons.add_circle_outline)); } return buttons; } Widget _panelBtn(String label, IconData icon) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: SizedBox( width: double.infinity, child: OutlinedButton.icon( onPressed: () => _onAgentAction(label), icon: Icon(icon, size: 20), label: Text(label), style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFF635BFF), side: const BorderSide(color: Color(0xFF635BFF)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), padding: const EdgeInsets.symmetric(vertical: 12), ), ), ), ); } void _onAgentAction(String label) { switch (label) { case '拍照': _pickImage(ImageSource.camera); break; case '上传照片': _pickImage(ImageSource.gallery); break; case '手动录入血压': _textCtrl.text = '血压 '; break; case '手动录入血糖': _textCtrl.text = '血糖 '; break; case '手动录入心率': _textCtrl.text = '心率 '; break; case '用药管理': pushRoute(ref, 'medications'); break; case '找医生': pushRoute(ref, 'doctors'); break; case '查看本周计划': pushRoute(ref, 'exercisePlan'); break; case '创建新计划': pushRoute(ref, 'exercisePlan'); break; } } Future _pickImage(ImageSource source) async { final picker = ImagePicker(); final picked = await picker.pickImage(source: source, imageQuality: 85); if (picked != null) { final token = await ref.read(apiClientProvider).accessToken; if (token == null) return; _textCtrl.text = '[图片已上传] $baseUrl/api/files/${picked.path.split('/').last}'; setState(() {}); } } void _showAttachmentPicker(BuildContext context) { showModalBottomSheet( context: context, builder: (ctx) => SafeArea( child: Wrap( children: [ ListTile( leading: const Icon(Icons.camera_alt), title: const Text('拍照'), onTap: () { Navigator.pop(ctx); _pickImage(ImageSource.camera); }, ), ListTile( leading: const Icon(Icons.photo_library), title: const Text('从相册选'), onTap: () { Navigator.pop(ctx); _pickImage(ImageSource.gallery); }, ), ListTile( leading: const Icon(Icons.attach_file), title: const Text('传文件'), onTap: () async { Navigator.pop(ctx); final result = await FilePicker.platform.pickFiles(); if (result != null && result.files.isNotEmpty) { _textCtrl.text = '[文件已选择] ${result.files.first.name}'; setState(() {}); } }, ), ], ), ), ); } Widget _buildInputBar() { return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Colors.white, border: Border(top: BorderSide(color: Colors.grey.shade200)), ), child: Row(children: [ IconButton(icon: const Icon(Icons.attach_file, size: 24, color: Color(0xFF666666)), onPressed: () => _showAttachmentPicker(context)), Expanded( child: TextField( controller: _textCtrl, decoration: const InputDecoration(hintText: '输入你想说的...', contentPadding: EdgeInsets.symmetric(horizontal: 12), border: InputBorder.none), onSubmitted: (_) => _sendMessage(), ), ), IconButton(icon: const Icon(Icons.send, size: 24, color: Color(0xFF635BFF)), onPressed: _sendMessage), ]), ); } }