Files
wushu/lib/views/discover_page.dart
Developer cba04235c8 release
2026-04-03 03:26:06 +08:00

478 lines
15 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../constants/app_constants.dart';
import '../config/app_config.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';
import '../services/get/discover_controller.dart';
import '../services/get/theme_controller.dart';
import 'home/set/home-load.dart';
/// 时间: 2025-03-21
/// 功能: 发现页面
/// 介绍: 展示发现内容,包括热门话题、推荐内容等
/// 最新变化: 2026-04-02 支持深色模式
class DiscoverPage extends StatefulWidget {
const DiscoverPage({super.key});
@override
State<DiscoverPage> createState() => _DiscoverPageState();
}
class _DiscoverPageState extends State<DiscoverPage>
with TickerProviderStateMixin {
late TabController _tabController;
final controller = Get.put(DiscoverController());
late ThemeController _themeController;
late AnimationController _tipsAnimationController;
late Animation<double> _tipsAnimation;
@override
void initState() {
super.initState();
_themeController = Get.find<ThemeController>();
GlobalTipsManager().init();
_tabController = TabController(
length: controller.categories.length,
vsync: this,
);
_tipsAnimationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_tipsAnimation = CurvedAnimation(
parent: _tipsAnimationController,
curve: Curves.easeInOut,
);
_tipsAnimationController.value = 1.0;
_tabController.addListener(() {
setState(() {});
});
}
@override
void dispose() {
_tabController.dispose();
_tipsAnimationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Obx(() {
final isDark = _themeController.isDarkModeRx.value;
return GetBuilder<DiscoverController>(
builder: (controller) {
if (!controller.isInitialized.value) {
return Scaffold(
backgroundColor: isDark ? const Color(0xFF121212) : Colors.white,
body: const Center(child: CircularProgressIndicator()),
);
}
return Scaffold(
backgroundColor: isDark ? const Color(0xFF121212) : Colors.white,
appBar: TabbedNavAppBar.build(
title: '发现',
tabLabels: controller.categories,
tabController: _tabController,
backgroundColor: isDark ? Colors.grey[900] : Colors.white,
foregroundColor: isDark
? Colors.white
: _themeController.currentThemeColor,
leading: controller.categories[_tabController.index] == '热门'
? _buildInfoButton(context, isDark)
: null,
actions: [
IconButton(
icon: Icon(
Icons.search,
color: isDark ? Colors.white : AppConstants.primaryColor,
),
onPressed: _showSearch,
),
],
),
body: Column(
children: [
ValueListenableBuilder<bool>(
valueListenable: GlobalTipsManager().enabledNotifier,
builder: (context, isGlobalTipsEnabled, child) {
if (controller.categories[_tabController.index] != '搜索' &&
isGlobalTipsEnabled &&
controller.showTips.value) {
return _buildTopicChips(controller, isDark);
}
return const SizedBox.shrink();
},
),
Expanded(
child: TabBarView(
controller: _tabController,
children: controller.categories.map((category) {
if (category == '分类') {
return const CategoryPage();
}
if (category == '热门') {
return const PopularPage();
}
if (category == '搜索') {
return const ActiveSearchPage();
}
if (category == '活跃') {
return const RatePage();
}
return _buildContentList(category, controller, isDark);
}).toList(),
),
),
],
),
);
},
);
});
}
Widget _buildTopicChips(DiscoverController controller, bool isDark) {
return SizeTransition(
sizeFactor: _tipsAnimation,
axisAlignment: -1.0,
child: FadeTransition(
opacity: _tipsAnimation,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
color: isDark ? const Color(0xFF1E1E1E) : Colors.grey[50],
child: Row(
children: [
Expanded(
child: Text(
'💡 探索更多精彩内容,发现你感兴趣的诗词世界',
style: TextStyle(
color: _themeController.currentThemeColor,
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
_tipsAnimationController.reverse();
await Future.delayed(const Duration(milliseconds: 300));
controller.toggleTips();
},
child: Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: isDark
? Colors.grey[800]
: Colors.grey.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
child: Icon(
Icons.close,
size: 16,
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
),
),
],
),
),
),
);
}
Widget _buildContentList(
String category,
DiscoverController controller,
bool isDark,
) {
final items = List.generate(20, (index) => index);
return RefreshIndicator(
onRefresh: controller.refreshContent,
child: ListView.separated(
// 添加底部内边距,让内容延伸到导航栏下方,实现玻璃效果
padding: EdgeInsets.only(
left: 16,
right: 16,
top: 16,
bottom: AppConfig.liquidGlassTotalHeight + 16,
),
itemCount: items.length,
separatorBuilder: (context, index) => const SizedBox(height: 12),
itemBuilder: (context, index) =>
_buildContentCard(context, index, category, controller, isDark),
),
);
}
Widget _buildContentCard(
BuildContext context,
int index,
String category,
DiscoverController controller,
bool isDark,
) {
return ResponsiveCard(
onTap: () => controller.showContentDetails(context, index, category),
backgroundColor: isDark ? const Color(0xFF1E1E1E) : Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
radius: 20,
backgroundColor: _themeController.currentThemeColor.withValues(
alpha: 0.1,
),
child: Icon(
Icons.person,
color: _themeController.currentThemeColor,
size: 20,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'用户${index + 1}',
style: TextStyle(
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : Colors.black87,
),
),
Text(
'${index + 1}小时前',
style: TextStyle(
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
),
],
),
),
IconButton(
icon: Icon(
Icons.more_horiz,
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
onPressed: () => controller.showMoreOptions(context, index),
),
],
),
const SizedBox(height: 12),
Text(
'这是$category分类下的精彩内容${index + 1}',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: isDark ? Colors.white : Colors.black87,
),
),
const SizedBox(height: 8),
Text(
'这里是内容的详细描述,包含了丰富的信息和有趣的内容。这个内容来自于$category分类,展示了最新的趋势和热门话题。',
style: TextStyle(
color: isDark ? Colors.grey[400] : 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: isDark
? AppConstants.secondaryColor.withValues(alpha: 0.2)
: AppConstants.secondaryColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
Icons.image,
size: 50,
color: isDark
? AppConstants.secondaryColor.withValues(alpha: 0.6)
: AppConstants.secondaryColor,
),
),
const SizedBox(height: 12),
Row(
children: [
_buildActionButton(
Icons.favorite_border,
'${(index + 1) * 23}',
() => controller.likeContent(index),
isDark,
),
const SizedBox(width: 16),
_buildActionButton(
Icons.chat_bubble_outline,
'${(index + 1) * 8}',
() => controller.commentContent(index),
isDark,
),
const SizedBox(width: 16),
_buildActionButton(
Icons.share,
'分享',
() => controller.shareContent(index),
isDark,
),
const Spacer(),
_buildActionButton(
Icons.bookmark_border,
'收藏',
() => controller.bookmarkContent(index),
isDark,
),
],
),
],
),
);
}
Widget _buildActionButton(
IconData icon,
String label,
VoidCallback onPressed,
bool isDark,
) {
return GestureDetector(
onTap: onPressed,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon,
size: 18,
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
const SizedBox(width: 4),
Text(
label,
style: TextStyle(
fontSize: 12,
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
),
],
),
);
}
void _showSearch() {
Get.to(const ActiveSearchPage());
}
Widget _buildInfoButton(BuildContext context, bool isDark) {
return Builder(
builder: (buttonContext) {
return IconButton(
icon: Icon(
Icons.info_outline,
color: isDark ? Colors.white : _themeController.currentThemeColor,
),
onPressed: () => _showHotInfoPopup(buttonContext, isDark),
);
},
);
}
void _showHotInfoPopup(BuildContext context, bool isDark) {
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,
);
late OverlayEntry infoOverlayEntry;
infoOverlayEntry = OverlayEntry(
builder: (context) => Positioned(
left: buttonPosition.dx,
top: buttonPosition.dy + button.size.height + 8,
child: Material(
color: Colors.transparent,
child: GestureDetector(
onTap: () {
infoOverlayEntry.remove();
},
child: Container(
width: 220,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: isDark ? 0.4 : 0.15),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.local_fire_department,
color: _themeController.currentThemeColor,
size: 20,
),
const SizedBox(width: 8),
Text(
'热门排行榜',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: isDark ? Colors.white : Colors.black87,
),
),
],
),
const SizedBox(height: 8),
Text(
'统计开源:来自本软件各个平台的数据,安卓 鸿蒙 web 小程序等平台。',
style: TextStyle(
fontSize: 12,
color: isDark ? Colors.grey[400] : Colors.grey[600],
height: 1.5,
),
),
],
),
),
),
),
),
);
Overlay.of(context).insert(infoOverlayEntry);
Future.delayed(const Duration(seconds: 3), () {
infoOverlayEntry.remove();
});
}
}