471 lines
14 KiB
Dart
471 lines
14 KiB
Dart
import 'package:flutter/material.dart';
|
||
import '../constants/app_constants.dart';
|
||
import '../utils/responsive_layout.dart';
|
||
import '../utils/flutter_compatibility_fix.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<DiscoverPage> createState() => _DiscoverPageState();
|
||
}
|
||
|
||
class _DiscoverPageState extends State<DiscoverPage>
|
||
with SingleTickerProviderStateMixin {
|
||
late TabController _tabController;
|
||
final List<String> _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<ScrollNotification>(
|
||
onNotification: (notification) {
|
||
if (notification is ScrollStartNotification) {
|
||
_removeInfoOverlay();
|
||
}
|
||
return false;
|
||
},
|
||
child: TabBarView(
|
||
controller: _tabController,
|
||
children: _categories.asMap().entries.map((entry) {
|
||
final index = entry.key;
|
||
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<void> _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();
|
||
});
|
||
}
|
||
}
|