import 'package:flutter/material.dart'; import '../constants/app_constants.dart'; import '../utils/responsive_layout.dart'; import '../widgets/tabbed_nav_app_bar.dart'; import 'active/active_search_page.dart'; import 'active/category_page.dart'; import 'active/popular_page.dart'; import 'active/rate.dart'; /// 时间: 2025-03-21 /// 功能: 发现页面 /// 介绍: 展示发现内容,包括热门话题、推荐内容等 /// 最新变化: 与收藏页共用 TabbedNavAppBar,压缩标题+Tab 高度,减少主导航子页顶部留白 class DiscoverPage extends StatefulWidget { const DiscoverPage({super.key}); @override State createState() => _DiscoverPageState(); } class _DiscoverPageState extends State with SingleTickerProviderStateMixin { late TabController _tabController; final List _categories = ['热门', '分类', '搜索', '活跃']; bool _showTips = true; OverlayEntry? _infoOverlayEntry; @override void initState() { super.initState(); _tabController = TabController(length: _categories.length, vsync: this); // 添加标签切换监听,以便更新UI _tabController.addListener(() { _removeInfoOverlay(); setState(() {}); }); } @override void dispose() { _removeInfoOverlay(); _tabController.dispose(); super.dispose(); } void _removeInfoOverlay() { _infoOverlayEntry?.remove(); _infoOverlayEntry = null; } @override Widget build(BuildContext context) { final isHotTab = _categories[_tabController.index] == '热门'; return Scaffold( appBar: TabbedNavAppBar.build( title: '发现', tabController: _tabController, tabLabels: _categories, leading: isHotTab ? _buildInfoButton(context) : null, actions: [ IconButton(icon: const Icon(Icons.search), onPressed: _showSearch), ], ), body: Column( children: [ // 只有非搜索标签时才显示话题chips if (_categories[_tabController.index] != '搜索' && _showTips) _buildTopicChips(), Expanded( child: NotificationListener( onNotification: (notification) { if (notification is ScrollStartNotification) { _removeInfoOverlay(); } return false; }, child: TabBarView( controller: _tabController, children: _categories.asMap().entries.map((entry) { final category = entry.value; // 搜索标签显示 ActiveSearchPage if (category == '搜索') { return const ActiveSearchPage(); } // 分类标签跳转到分类页面 if (category == '分类') { return const CategoryPage(); } // 热门标签显示排行榜页面 if (category == '热门') { return const PopularPage(); } // 活跃标签显示活跃统计页面 if (category == '活跃') { return const RatePage(); } // 其他标签显示原有内容 return _buildContentList(category); }).toList(), ), ), ), ], ), ); } Widget _buildTopicChips() { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( children: [ Expanded( child: Text( '💡 探索更多精彩内容,发现你感兴趣的诗词世界', style: TextStyle( color: AppConstants.primaryColor, fontSize: 14, fontWeight: FontWeight.w400, ), ), ), GestureDetector( onTap: () { setState(() { _showTips = false; }); }, child: Container( width: 30, height: 30, decoration: BoxDecoration( color: Colors.grey.withValues(alpha: 0.1), shape: BoxShape.circle, ), child: Icon(Icons.close, size: 16, color: Colors.grey[600]), ), ), ], ), ); } Widget _buildContentList(String category) { final items = List.generate(10, (index) => index); return RefreshIndicator( onRefresh: _refreshContent, child: ListView.separated( padding: const EdgeInsets.all(16), itemCount: items.length, separatorBuilder: (context, index) => const SizedBox(height: 12), itemBuilder: (context, index) => _buildContentCard(context, index, category), ), ); } Widget _buildContentCard(BuildContext context, int index, String category) { return ResponsiveCard( onTap: () => _showContentDetails(context, index, category), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ CircleAvatar( radius: 20, backgroundColor: AppConstants.primaryColor.withValues( alpha: 0.1, ), child: Icon( Icons.person, color: AppConstants.primaryColor, size: 20, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '用户${index + 1}', style: Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.bold, ), ), Text( '${index + 1}小时前', style: Theme.of( context, ).textTheme.bodySmall?.copyWith(color: Colors.grey[600]), ), ], ), ), IconButton( icon: const Icon(Icons.more_horiz), onPressed: () => _showMoreOptions(context, index), ), ], ), const SizedBox(height: 12), Text( '这是$category分类下的精彩内容${index + 1}', style: Theme.of( context, ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600), ), const SizedBox(height: 8), Text( '这里是内容的详细描述,包含了丰富的信息和有趣的内容。这个内容来自于$category分类,展示了最新的趋势和热门话题。', style: Theme.of( context, ).textTheme.bodyMedium?.copyWith(color: Colors.grey[700]), maxLines: 3, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 12), if (index % 3 == 0) Container( width: double.infinity, height: 200, decoration: BoxDecoration( color: AppConstants.secondaryColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), ), child: Icon( Icons.image, size: 50, color: AppConstants.secondaryColor, ), ), const SizedBox(height: 12), Row( children: [ _buildActionButton( Icons.favorite_border, '${(index + 1) * 23}', () => _likeContent(index), ), const SizedBox(width: 16), _buildActionButton( Icons.chat_bubble_outline, '${(index + 1) * 8}', () => _commentContent(index), ), const SizedBox(width: 16), _buildActionButton(Icons.share, '分享', () => _shareContent(index)), const Spacer(), _buildActionButton( Icons.bookmark_border, '收藏', () => _bookmarkContent(index), ), ], ), ], ), ); } Widget _buildActionButton( IconData icon, String label, VoidCallback onPressed, ) { return GestureDetector( onTap: onPressed, child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 18, color: Colors.grey[600]), const SizedBox(width: 4), Text(label, style: TextStyle(fontSize: 12, color: Colors.grey[600])), ], ), ); } Future _refreshContent() async { await Future.delayed(const Duration(seconds: 1)); ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('内容已刷新'))); } void _showSearch() { Navigator.of( context, ).push(MaterialPageRoute(builder: (context) => const ActiveSearchPage())); } void _showContentDetails(BuildContext context, int index, String category) { showDialog( context: context, builder: (context) => AlertDialog( title: Text('$category - 内容${index + 1}'), content: Text('这是$category分类下内容${index + 1}的详细信息。'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('关闭'), ), ], ), ); } void _showMoreOptions(BuildContext context, int index) { showModalBottomSheet( context: context, builder: (context) => Container( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( leading: const Icon(Icons.report), title: const Text('举报'), onTap: () { Navigator.pop(context); ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('举报内容'))); }, ), ListTile( leading: const Icon(Icons.block), title: const Text('屏蔽用户'), onTap: () { Navigator.pop(context); ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('屏蔽用户'))); }, ), ListTile( leading: const Icon(Icons.link), title: const Text('复制链接'), onTap: () { Navigator.pop(context); ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('链接已复制'))); }, ), ], ), ), ); } void _likeContent(int index) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('点赞了内容${index + 1}'))); } void _commentContent(int index) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('评论了内容${index + 1}'))); } void _shareContent(int index) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('分享了内容${index + 1}'))); } void _bookmarkContent(int index) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text('收藏了内容${index + 1}'))); } Widget _buildInfoButton(BuildContext context) { return Builder( builder: (buttonContext) { return IconButton( icon: const Icon(Icons.info_outline), onPressed: () => _showHotInfoPopup(buttonContext), ); }, ); } void _showHotInfoPopup(BuildContext context) { _removeInfoOverlay(); final RenderBox button = context.findRenderObject() as RenderBox; final RenderBox overlay = Navigator.of(context).overlay!.context.findRenderObject() as RenderBox; final Offset buttonPosition = button.localToGlobal( Offset.zero, ancestor: overlay, ); _infoOverlayEntry = OverlayEntry( builder: (context) => Positioned( left: buttonPosition.dx, top: buttonPosition.dy + button.size.height + 8, child: Material( color: Colors.transparent, child: GestureDetector( onTap: _removeInfoOverlay, child: Container( width: 220, padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.15), blurRadius: 12, offset: const Offset(0, 4), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.local_fire_department, color: AppConstants.primaryColor, size: 20, ), const SizedBox(width: 8), const Text( '热门排行榜', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14, ), ), ], ), const SizedBox(height: 8), Text( '展示诗词的浏览量和点赞数排行,包括总榜、日榜、月榜三种类型。帮助您发现最受欢迎的诗词作品。', style: TextStyle( fontSize: 12, color: Colors.grey[600], height: 1.5, ), ), ], ), ), ), ), ), ); Overlay.of(context).insert(_infoOverlayEntry!); Future.delayed(const Duration(seconds: 3), () { _removeInfoOverlay(); }); } }