深色模式、首页设置页面和功能优化

This commit is contained in:
Developer
2026-04-02 07:06:55 +08:00
parent f0a62ed68b
commit 954d173329
88 changed files with 12157 additions and 7578 deletions

View File

@@ -1,17 +1,21 @@
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 '../controllers/shared_preferences_storage_controller.dart';
import '../services/get/discover_controller.dart';
import '../services/get/theme_controller.dart';
import 'home/set/home-load.dart';
/// 时间: 2025-03-21
/// 功能: 发现页面
/// 介绍: 展示发现内容,包括热门话题、推荐内容等
/// 最新变化: 与收藏页共用 TabbedNavAppBar压缩标题+Tab 高度,减少主导航子页顶部留白
/// 最新变化: 2026-04-02 支持深色模式
class DiscoverPage extends StatefulWidget {
const DiscoverPage({super.key});
@@ -22,125 +26,113 @@ class DiscoverPage extends StatefulWidget {
class _DiscoverPageState extends State<DiscoverPage>
with SingleTickerProviderStateMixin {
TabController? _tabController;
List<String> _categories = ['分类', '热门', '搜索'];
bool _showTips = true;
bool _isDeveloperMode = false;
bool _isInitialized = false;
OverlayEntry? _infoOverlayEntry;
late TabController _tabController;
final controller = Get.put(DiscoverController());
late ThemeController _themeController;
@override
void initState() {
super.initState();
_loadDeveloperMode();
}
Future<void> _loadDeveloperMode() async {
final isEnabled = await SharedPreferencesStorageController.getBool(
'developer_mode_enabled',
defaultValue: false,
_themeController = Get.find<ThemeController>();
GlobalTipsManager().init();
_tabController = TabController(
length: controller.categories.length,
vsync: this,
);
if (mounted) {
setState(() {
_isDeveloperMode = isEnabled;
_updateCategories();
});
}
}
void _updateCategories() {
setState(() {
_categories = ['分类', '热门', '搜索'];
if (_isDeveloperMode) {
_categories.add('活跃');
}
_tabController?.dispose();
_tabController = TabController(length: _categories.length, vsync: this);
_tabController!.addListener(() {
_removeInfoOverlay();
setState(() {});
});
_isInitialized = true;
_tabController.addListener(() {
setState(() {});
});
}
@override
void dispose() {
_removeInfoOverlay();
_tabController?.dispose();
_tabController.dispose();
super.dispose();
}
void _removeInfoOverlay() {
_infoOverlayEntry?.remove();
_infoOverlayEntry = null;
}
@override
Widget build(BuildContext context) {
if (!_isInitialized) {
return const Scaffold(body: Center(child: CircularProgressIndicator()));
}
return Obx(() {
final isDark = _themeController.isDarkModeRx.value;
final isHotTab = _categories[_tabController!.index] == '热门';
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(
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 category = entry.value;
// 分类标签显示分类页面
if (category == '分类') {
return const CategoryPage();
}
// 热门标签显示排行榜页面
if (category == '热门') {
return const PopularPage();
}
// 搜索标签显示 ActiveSearchPage
if (category == '搜索') {
return const ActiveSearchPage();
}
// 活跃标签显示活跃统计页面
if (category == '活跃') {
return const RatePage();
}
// 其他标签显示原有内容
return _buildContentList(category);
}).toList(),
),
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
: AppConstants.primaryColor,
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() {
Widget _buildTopicChips(DiscoverController controller, bool isDark) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
color: isDark ? const Color(0xFF1E1E1E) : Colors.grey[50],
child: Row(
children: [
Expanded(
@@ -154,19 +146,24 @@ class _DiscoverPageState extends State<DiscoverPage>
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() {
_showTips = false;
});
controller.toggleTips();
},
child: Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: Colors.grey.withValues(alpha: 0.1),
color: isDark
? Colors.grey[800]
: Colors.grey.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
child: Icon(Icons.close, size: 16, color: Colors.grey[600]),
child: Icon(
Icons.close,
size: 16,
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
),
),
],
@@ -174,24 +171,41 @@ class _DiscoverPageState extends State<DiscoverPage>
);
}
Widget _buildContentList(String category) {
final items = List.generate(10, (index) => index);
Widget _buildContentList(
String category,
DiscoverController controller,
bool isDark,
) {
final items = List.generate(20, (index) => index);
return RefreshIndicator(
onRefresh: _refreshContent,
onRefresh: controller.refreshContent,
child: ListView.separated(
padding: const EdgeInsets.all(16),
// 添加底部内边距,让内容延伸到导航栏下方,实现玻璃效果
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),
_buildContentCard(context, index, category, controller, isDark),
),
);
}
Widget _buildContentCard(BuildContext context, int index, String category) {
Widget _buildContentCard(
BuildContext context,
int index,
String category,
DiscoverController controller,
bool isDark,
) {
return ResponsiveCard(
onTap: () => _showContentDetails(context, index, category),
onTap: () => controller.showContentDetails(context, index, category),
backgroundColor: isDark ? const Color(0xFF1E1E1E) : Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -215,38 +229,44 @@ class _DiscoverPageState extends State<DiscoverPage>
children: [
Text(
'用户${index + 1}',
style: Theme.of(context).textTheme.titleSmall?.copyWith(
style: TextStyle(
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : Colors.black87,
),
),
Text(
'${index + 1}小时前',
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(color: Colors.grey[600]),
style: TextStyle(
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
),
],
),
),
IconButton(
icon: const Icon(Icons.more_horiz),
onPressed: () => _showMoreOptions(context, index),
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: Theme.of(
context,
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600),
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: isDark ? Colors.white : Colors.black87,
),
),
const SizedBox(height: 8),
Text(
'这里是内容的详细描述,包含了丰富的信息和有趣的内容。这个内容来自于$category分类,展示了最新的趋势和热门话题。',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: Colors.grey[700]),
style: TextStyle(
color: isDark ? Colors.grey[400] : Colors.grey[700],
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
@@ -256,13 +276,17 @@ class _DiscoverPageState extends State<DiscoverPage>
width: double.infinity,
height: 200,
decoration: BoxDecoration(
color: AppConstants.secondaryColor.withValues(alpha: 0.1),
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: AppConstants.secondaryColor,
color: isDark
? AppConstants.secondaryColor.withValues(alpha: 0.6)
: AppConstants.secondaryColor,
),
),
const SizedBox(height: 12),
@@ -271,21 +295,29 @@ class _DiscoverPageState extends State<DiscoverPage>
_buildActionButton(
Icons.favorite_border,
'${(index + 1) * 23}',
() => _likeContent(index),
() => controller.likeContent(index),
isDark,
),
const SizedBox(width: 16),
_buildActionButton(
Icons.chat_bubble_outline,
'${(index + 1) * 8}',
() => _commentContent(index),
() => controller.commentContent(index),
isDark,
),
const SizedBox(width: 16),
_buildActionButton(Icons.share, '分享', () => _shareContent(index)),
_buildActionButton(
Icons.share,
'分享',
() => controller.shareContent(index),
isDark,
),
const Spacer(),
_buildActionButton(
Icons.bookmark_border,
'收藏',
() => _bookmarkContent(index),
() => controller.bookmarkContent(index),
isDark,
),
],
),
@@ -298,133 +330,50 @@ class _DiscoverPageState extends State<DiscoverPage>
IconData icon,
String label,
VoidCallback onPressed,
bool isDark,
) {
return GestureDetector(
onTap: onPressed,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 18, color: Colors.grey[600]),
Icon(
icon,
size: 18,
color: isDark ? Colors.grey[400] : 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));
if (mounted) {
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('关闭'),
Text(
label,
style: TextStyle(
fontSize: 12,
color: isDark ? Colors.grey[400] : Colors.grey[600],
),
),
],
),
);
}
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 _showSearch() {
Get.to(const ActiveSearchPage());
}
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) {
Widget _buildInfoButton(BuildContext context, bool isDark) {
return Builder(
builder: (buttonContext) {
return IconButton(
icon: const Icon(Icons.info_outline),
onPressed: () => _showHotInfoPopup(buttonContext),
icon: Icon(
Icons.info_outline,
color: isDark ? Colors.white : AppConstants.primaryColor,
),
onPressed: () => _showHotInfoPopup(buttonContext, isDark),
);
},
);
}
void _showHotInfoPopup(BuildContext context) {
_removeInfoOverlay();
void _showHotInfoPopup(BuildContext context, bool isDark) {
final RenderBox button = context.findRenderObject() as RenderBox;
final RenderBox overlay =
Navigator.of(context).overlay!.context.findRenderObject() as RenderBox;
@@ -433,23 +382,26 @@ class _DiscoverPageState extends State<DiscoverPage>
ancestor: overlay,
);
_infoOverlayEntry = OverlayEntry(
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: _removeInfoOverlay,
onTap: () {
infoOverlayEntry.remove();
},
child: Container(
width: 220,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.15),
color: Colors.black.withValues(alpha: isDark ? 0.4 : 0.15),
blurRadius: 12,
offset: const Offset(0, 4),
),
@@ -466,11 +418,12 @@ class _DiscoverPageState extends State<DiscoverPage>
size: 20,
),
const SizedBox(width: 8),
const Text(
Text(
'热门排行榜',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: isDark ? Colors.white : Colors.black87,
),
),
],
@@ -480,7 +433,7 @@ class _DiscoverPageState extends State<DiscoverPage>
'展示诗词的浏览量和点赞数排行,包括总榜、日榜、月榜三种类型。帮助您发现最受欢迎的诗词作品。',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
color: isDark ? Colors.grey[400] : Colors.grey[600],
height: 1.5,
),
),
@@ -492,10 +445,10 @@ class _DiscoverPageState extends State<DiscoverPage>
),
);
Overlay.of(context).insert(_infoOverlayEntry!);
Overlay.of(context).insert(infoOverlayEntry);
Future.delayed(const Duration(seconds: 3), () {
_removeInfoOverlay();
infoOverlayEntry.remove();
});
}
}