深色模式、首页设置页面和功能优化
This commit is contained in:
@@ -5,8 +5,10 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../constants/app_constants.dart';
|
||||
import '../../../services/get/theme_controller.dart';
|
||||
|
||||
class BugListPage extends StatefulWidget {
|
||||
const BugListPage({super.key});
|
||||
@@ -16,6 +18,7 @@ class BugListPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _BugListPageState extends State<BugListPage> {
|
||||
final ThemeController _themeController = Get.find<ThemeController>();
|
||||
// 模拟bug数据
|
||||
final List<Map<String, dynamic>> _bugs = [
|
||||
{
|
||||
@@ -178,7 +181,6 @@ class _BugListPageState extends State<BugListPage> {
|
||||
];
|
||||
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
bool _isRefreshing = false;
|
||||
|
||||
// 切换bug展开状态
|
||||
void _toggleBugExpanded(int bugId) {
|
||||
@@ -268,57 +270,52 @@ class _BugListPageState extends State<BugListPage> {
|
||||
}
|
||||
|
||||
Future<void> _refresh() async {
|
||||
setState(() {
|
||||
_isRefreshing = true;
|
||||
});
|
||||
|
||||
// 模拟网络请求延迟
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
|
||||
setState(() {
|
||||
_isRefreshing = false;
|
||||
});
|
||||
|
||||
HapticFeedback.lightImpact();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// 顶部拖拽条和标题
|
||||
_buildHeader(),
|
||||
// bug列表
|
||||
Expanded(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: _refresh,
|
||||
color: AppConstants.primaryColor,
|
||||
child: ListView.builder(
|
||||
controller: _scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: const EdgeInsets.all(16),
|
||||
itemCount: _bugs.length + 1,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == _bugs.length) {
|
||||
return _buildFooter();
|
||||
}
|
||||
final bug = _bugs[index];
|
||||
return _buildBugItem(bug);
|
||||
},
|
||||
return Obx(() {
|
||||
final isDark = _themeController.isDarkMode;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: isDark ? const Color(0xFF1A1A1A) : Colors.white,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// 顶部拖拽条和标题
|
||||
_buildHeader(isDark),
|
||||
// bug列表
|
||||
Expanded(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: _refresh,
|
||||
color: AppConstants.primaryColor,
|
||||
child: ListView.builder(
|
||||
controller: _scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: const EdgeInsets.all(16),
|
||||
itemCount: _bugs.length + 1,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == _bugs.length) {
|
||||
return _buildFooter(isDark);
|
||||
}
|
||||
final bug = _bugs[index];
|
||||
return _buildBugItem(bug, isDark);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildHeader() {
|
||||
Widget _buildHeader(bool isDark) {
|
||||
return Column(
|
||||
children: [
|
||||
// 拖拽条
|
||||
@@ -327,7 +324,7 @@ class _BugListPageState extends State<BugListPage> {
|
||||
height: 4,
|
||||
margin: const EdgeInsets.only(top: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
color: isDark ? Colors.grey[600] : Colors.grey[300],
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
@@ -354,17 +351,20 @@ class _BugListPageState extends State<BugListPage> {
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('关闭'),
|
||||
child: Text(
|
||||
'关闭',
|
||||
style: TextStyle(color: isDark ? Colors.white : null),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
Divider(height: 1, color: isDark ? Colors.grey[700] : null),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFooter() {
|
||||
Widget _buildFooter(bool isDark) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24),
|
||||
child: Column(
|
||||
@@ -372,39 +372,55 @@ class _BugListPageState extends State<BugListPage> {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(width: 40, height: 1, color: Colors.grey[300]),
|
||||
Container(
|
||||
width: 40,
|
||||
height: 1,
|
||||
color: isDark ? Colors.grey[600] : Colors.grey[300],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Text(
|
||||
'已经到底了',
|
||||
style: TextStyle(fontSize: 13, color: Colors.grey[500]),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: isDark ? Colors.grey[400] : Colors.grey[500],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(width: 40, height: 1, color: Colors.grey[300]),
|
||||
Container(
|
||||
width: 40,
|
||||
height: 1,
|
||||
color: isDark ? Colors.grey[600] : Colors.grey[300],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'共 ${_bugs.length} 个已知问题',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[400]),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isDark ? Colors.grey[500] : Colors.grey[400],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBugItem(Map<String, dynamic> bug) {
|
||||
Widget _buildBugItem(Map<String, dynamic> bug, bool isDark) {
|
||||
final bool isExpanded = bug['expanded'] ?? false;
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: Colors.grey[200]!),
|
||||
border: Border.all(
|
||||
color: isDark ? Colors.grey[700]! : Colors.grey[200]!,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.05),
|
||||
color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.05),
|
||||
blurRadius: 5,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -426,10 +442,10 @@ class _BugListPageState extends State<BugListPage> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
bug['title'] ?? '未知问题',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black87,
|
||||
color: isDark ? Colors.white : Colors.black87,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -464,9 +480,9 @@ class _BugListPageState extends State<BugListPage> {
|
||||
// 问题描述
|
||||
Text(
|
||||
bug['description'] ?? '暂无描述',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.black54,
|
||||
color: isDark ? Colors.grey[400] : Colors.black54,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
@@ -506,11 +522,18 @@ class _BugListPageState extends State<BugListPage> {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Icon(Icons.people, size: 14, color: Colors.grey[600]),
|
||||
Icon(
|
||||
Icons.people,
|
||||
size: 14,
|
||||
color: isDark ? Colors.grey[400] : Colors.grey[600],
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
bug['affectedUsers'] ?? '未知用户',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isDark ? Colors.grey[400] : Colors.grey[600],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -585,11 +608,11 @@ class _BugListPageState extends State<BugListPage> {
|
||||
),
|
||||
// 解决方案区域(可展开/收起)
|
||||
if (isExpanded) ...[
|
||||
const Divider(height: 1),
|
||||
Divider(height: 1, color: isDark ? Colors.grey[700] : null),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[50],
|
||||
color: isDark ? const Color(0xFF333333) : Colors.grey[50],
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
@@ -619,9 +642,9 @@ class _BugListPageState extends State<BugListPage> {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
bug['solution'] ?? '暂无解决方案',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.black54,
|
||||
color: isDark ? Colors.grey[400] : Colors.black54,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
@@ -629,18 +652,32 @@ class _BugListPageState extends State<BugListPage> {
|
||||
// 时间信息
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.schedule, size: 14, color: Colors.grey[600]),
|
||||
Icon(
|
||||
Icons.schedule,
|
||||
size: 14,
|
||||
color: isDark ? Colors.grey[400] : Colors.grey[600],
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'预计解决: ${bug['resolveTime'] ?? '待定'}',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isDark ? Colors.grey[400] : Colors.grey[600],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Icon(Icons.report, size: 14, color: Colors.grey[600]),
|
||||
Icon(
|
||||
Icons.report,
|
||||
size: 14,
|
||||
color: isDark ? Colors.grey[400] : Colors.grey[600],
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'报告时间: ${bug['reportTime'] ?? '未知'}',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isDark ? Colors.grey[400] : Colors.grey[600],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -650,11 +687,11 @@ class _BugListPageState extends State<BugListPage> {
|
||||
],
|
||||
// 复现步骤区域(可展开/收起)
|
||||
if (bug['reproductionExpanded']) ...[
|
||||
const Divider(height: 1),
|
||||
Divider(height: 1, color: isDark ? Colors.grey[700] : null),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[50],
|
||||
color: isDark ? const Color(0xFF333333) : Colors.grey[50],
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
@@ -684,9 +721,9 @@ class _BugListPageState extends State<BugListPage> {
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
bug['reproduction'] ?? '暂无复现步骤',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.black54,
|
||||
color: isDark ? Colors.grey[400] : Colors.black54,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -6,9 +6,11 @@ library;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../constants/app_constants.dart';
|
||||
import '../../../utils/http/http_client.dart';
|
||||
import '../../../services/network_listener_service.dart';
|
||||
import '../../../services/get/theme_controller.dart';
|
||||
import 'server_info_dialog.dart';
|
||||
|
||||
class EntirePage extends StatefulWidget {
|
||||
@@ -20,6 +22,7 @@ class EntirePage extends StatefulWidget {
|
||||
|
||||
class _EntirePageState extends State<EntirePage>
|
||||
with NetworkListenerMixin, SingleTickerProviderStateMixin {
|
||||
final ThemeController _themeController = Get.find<ThemeController>();
|
||||
Map<String, dynamic>? _statsData;
|
||||
String? _errorMessage;
|
||||
late AnimationController _animationController;
|
||||
@@ -124,31 +127,36 @@ class _EntirePageState extends State<EntirePage>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.dark,
|
||||
child: Scaffold(
|
||||
backgroundColor: const Color(0xFFF2F2F7),
|
||||
appBar: _buildAppBar(),
|
||||
body: _buildBody(),
|
||||
),
|
||||
);
|
||||
return Obx(() {
|
||||
final isDark = _themeController.isDarkMode;
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
|
||||
child: Scaffold(
|
||||
backgroundColor: isDark
|
||||
? const Color(0xFF1A1A1A)
|
||||
: const Color(0xFFF2F2F7),
|
||||
appBar: _buildAppBar(isDark),
|
||||
body: _buildBody(isDark),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
PreferredSizeWidget _buildAppBar() {
|
||||
PreferredSizeWidget _buildAppBar(bool isDark) {
|
||||
return AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white,
|
||||
elevation: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(
|
||||
icon: Icon(
|
||||
Icons.arrow_back_ios,
|
||||
color: AppConstants.primaryColor,
|
||||
color: isDark ? Colors.white : AppConstants.primaryColor,
|
||||
),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
title: const Text(
|
||||
title: Text(
|
||||
'全站统计',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
color: isDark ? Colors.white : Colors.black,
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -156,9 +164,9 @@ class _EntirePageState extends State<EntirePage>
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
icon: Icon(
|
||||
Icons.info_outline,
|
||||
color: AppConstants.primaryColor,
|
||||
color: isDark ? Colors.white : AppConstants.primaryColor,
|
||||
),
|
||||
onPressed: _showServerInfo,
|
||||
tooltip: '服务器信息',
|
||||
@@ -166,64 +174,68 @@ class _EntirePageState extends State<EntirePage>
|
||||
],
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(0.5),
|
||||
child: Container(height: 0.5, color: const Color(0xFFE5E5EA)),
|
||||
child: Container(
|
||||
height: 0.5,
|
||||
color: isDark ? Colors.grey[700] : const Color(0xFFE5E5EA),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
Widget _buildBody(bool isDark) {
|
||||
if (_errorMessage != null) {
|
||||
return _buildErrorView();
|
||||
return _buildErrorView(isDark);
|
||||
}
|
||||
|
||||
if (_statsData == null) {
|
||||
return _buildSkeletonView();
|
||||
return _buildSkeletonView(isDark);
|
||||
}
|
||||
|
||||
return _buildStatsContent();
|
||||
return _buildStatsContent(isDark);
|
||||
}
|
||||
|
||||
Widget _buildSkeletonBox({
|
||||
double width = double.infinity,
|
||||
double height = 16,
|
||||
double radius = 8,
|
||||
bool isDark = false,
|
||||
}) {
|
||||
return Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFE5E5EA),
|
||||
color: isDark ? Colors.grey[700] : const Color(0xFFE5E5EA),
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSkeletonView() {
|
||||
Widget _buildSkeletonView(bool isDark) {
|
||||
return FadeTransition(
|
||||
opacity: _fadeAnimation,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
_buildSkeletonHeaderCard(),
|
||||
_buildSkeletonHeaderCard(isDark),
|
||||
const SizedBox(height: 16),
|
||||
_buildSkeletonSection(),
|
||||
_buildSkeletonSection(isDark),
|
||||
const SizedBox(height: 16),
|
||||
_buildSkeletonSection(),
|
||||
_buildSkeletonSection(isDark),
|
||||
const SizedBox(height: 16),
|
||||
_buildSkeletonSection(),
|
||||
_buildSkeletonSection(isDark),
|
||||
const SizedBox(height: 16),
|
||||
_buildSkeletonBuildTimeCard(),
|
||||
_buildSkeletonBuildTimeCard(isDark),
|
||||
const SizedBox(height: 32),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSkeletonHeaderCard() {
|
||||
Widget _buildSkeletonHeaderCard(bool isDark) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFE5E5EA),
|
||||
color: isDark ? Colors.grey[700] : const Color(0xFFE5E5EA),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
@@ -231,20 +243,25 @@ class _EntirePageState extends State<EntirePage>
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
_buildSkeletonBox(width: 28, height: 28, radius: 14),
|
||||
_buildSkeletonBox(
|
||||
width: 28,
|
||||
height: 28,
|
||||
radius: 14,
|
||||
isDark: isDark,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_buildSkeletonBox(width: 100, height: 22),
|
||||
_buildSkeletonBox(width: 100, height: 22, isDark: isDark),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildSkeletonBox(width: 200, height: 14),
|
||||
_buildSkeletonBox(width: 200, height: 14, isDark: isDark),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_buildSkeletonBox(width: 60, height: 40),
|
||||
_buildSkeletonBox(width: 60, height: 40),
|
||||
_buildSkeletonBox(width: 60, height: 40),
|
||||
_buildSkeletonBox(width: 60, height: 40, isDark: isDark),
|
||||
_buildSkeletonBox(width: 60, height: 40, isDark: isDark),
|
||||
_buildSkeletonBox(width: 60, height: 40, isDark: isDark),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -252,15 +269,15 @@ class _EntirePageState extends State<EntirePage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSkeletonSection() {
|
||||
Widget _buildSkeletonSection(bool isDark) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.04),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -271,9 +288,14 @@ class _EntirePageState extends State<EntirePage>
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
_buildSkeletonBox(width: 20, height: 20, radius: 10),
|
||||
_buildSkeletonBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
radius: 10,
|
||||
isDark: isDark,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_buildSkeletonBox(width: 80, height: 16),
|
||||
_buildSkeletonBox(width: 80, height: 16, isDark: isDark),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
@@ -284,18 +306,21 @@ class _EntirePageState extends State<EntirePage>
|
||||
childAspectRatio: 1.0,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
children: List.generate(9, (index) => _buildSkeletonCountItem()),
|
||||
children: List.generate(
|
||||
9,
|
||||
(index) => _buildSkeletonCountItem(isDark),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSkeletonCountItem() {
|
||||
Widget _buildSkeletonCountItem(bool isDark) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF2F2F7),
|
||||
color: isDark ? const Color(0xFF333333) : const Color(0xFFF2F2F7),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
@@ -309,31 +334,39 @@ class _EntirePageState extends State<EntirePage>
|
||||
width: double.infinity,
|
||||
height: 28,
|
||||
radius: 8,
|
||||
isDark: isDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: _buildSkeletonBox(width: double.infinity, height: 22),
|
||||
child: _buildSkeletonBox(
|
||||
width: double.infinity,
|
||||
height: 22,
|
||||
isDark: isDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Expanded(flex: 1, child: _buildSkeletonBox(width: 50, height: 12)),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: _buildSkeletonBox(width: 50, height: 12, isDark: isDark),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSkeletonBuildTimeCard() {
|
||||
Widget _buildSkeletonBuildTimeCard(bool isDark) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.04),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -341,15 +374,15 @@ class _EntirePageState extends State<EntirePage>
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
_buildSkeletonBox(width: 40, height: 40, radius: 10),
|
||||
_buildSkeletonBox(width: 40, height: 40, radius: 10, isDark: isDark),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildSkeletonBox(width: 60, height: 14),
|
||||
_buildSkeletonBox(width: 60, height: 14, isDark: isDark),
|
||||
const SizedBox(height: 4),
|
||||
_buildSkeletonBox(width: 150, height: 16),
|
||||
_buildSkeletonBox(width: 150, height: 16, isDark: isDark),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -358,7 +391,7 @@ class _EntirePageState extends State<EntirePage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildErrorView() {
|
||||
Widget _buildErrorView(bool isDark) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
@@ -381,7 +414,10 @@ class _EntirePageState extends State<EntirePage>
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
_errorMessage ?? '加载失败',
|
||||
style: const TextStyle(color: Color(0xFF8E8E93), fontSize: 14),
|
||||
style: TextStyle(
|
||||
color: isDark ? Colors.grey[400] : const Color(0xFF8E8E93),
|
||||
fontSize: 14,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
@@ -406,7 +442,7 @@ class _EntirePageState extends State<EntirePage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatsContent() {
|
||||
Widget _buildStatsContent(bool isDark) {
|
||||
return FadeTransition(
|
||||
opacity: _fadeAnimation,
|
||||
child: RefreshIndicator(
|
||||
@@ -417,13 +453,13 @@ class _EntirePageState extends State<EntirePage>
|
||||
children: [
|
||||
_buildHeaderCard(),
|
||||
const SizedBox(height: 16),
|
||||
_buildHotSection(),
|
||||
_buildHotSection(isDark),
|
||||
const SizedBox(height: 16),
|
||||
_buildCountSection(),
|
||||
_buildCountSection(isDark),
|
||||
const SizedBox(height: 16),
|
||||
_buildTopContentSection(),
|
||||
_buildTopContentSection(isDark),
|
||||
const SizedBox(height: 16),
|
||||
_buildBuildTimeCard(),
|
||||
_buildBuildTimeCard(isDark),
|
||||
const SizedBox(height: 32),
|
||||
],
|
||||
),
|
||||
@@ -543,13 +579,13 @@ class _EntirePageState extends State<EntirePage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCountSection() {
|
||||
Widget _buildCountSection(bool isDark) {
|
||||
return _buildSection('数量统计', Icons.format_list_numbered, [
|
||||
_buildCountGrid(),
|
||||
]);
|
||||
_buildCountGrid(isDark),
|
||||
], isDark);
|
||||
}
|
||||
|
||||
Widget _buildCountGrid() {
|
||||
Widget _buildCountGrid(bool isDark) {
|
||||
final counts = [
|
||||
{
|
||||
'label': '项目',
|
||||
@@ -634,6 +670,7 @@ class _EntirePageState extends State<EntirePage>
|
||||
item['icon'] as IconData,
|
||||
item['color'] as Color,
|
||||
item['showIcon'] as bool,
|
||||
isDark,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -645,15 +682,16 @@ class _EntirePageState extends State<EntirePage>
|
||||
IconData icon,
|
||||
Color color,
|
||||
bool showIcon,
|
||||
bool isDark,
|
||||
) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.04),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -682,10 +720,10 @@ class _EntirePageState extends State<EntirePage>
|
||||
Expanded(
|
||||
child: Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
color: isDark ? Colors.white : Colors.black,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -700,7 +738,10 @@ class _EntirePageState extends State<EntirePage>
|
||||
child: Center(
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(fontSize: 12, color: Color(0xFF3C3C43)),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: isDark ? Colors.grey[400] : const Color(0xFF3C3C43),
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.center,
|
||||
@@ -712,13 +753,14 @@ class _EntirePageState extends State<EntirePage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHotSection() {
|
||||
Widget _buildHotSection(bool isDark) {
|
||||
return _buildSection('热度统计', Icons.trending_up, [
|
||||
_buildHotItem(
|
||||
'累计热度',
|
||||
_statsData?['cumulative_hits']?.toString() ?? '0',
|
||||
Icons.local_fire_department,
|
||||
const Color(0xFFFF9500),
|
||||
isDark,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildHotItem(
|
||||
@@ -726,19 +768,26 @@ class _EntirePageState extends State<EntirePage>
|
||||
_statsData?['cumulative_likes']?.toString() ?? '0',
|
||||
Icons.favorite,
|
||||
const Color(0xFFFF2D55),
|
||||
isDark,
|
||||
),
|
||||
]);
|
||||
], isDark);
|
||||
}
|
||||
|
||||
Widget _buildHotItem(String label, String value, IconData icon, Color color) {
|
||||
Widget _buildHotItem(
|
||||
String label,
|
||||
String value,
|
||||
IconData icon,
|
||||
Color color,
|
||||
bool isDark,
|
||||
) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.04),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -762,18 +811,18 @@ class _EntirePageState extends State<EntirePage>
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Color(0xFF8E8E93),
|
||||
color: isDark ? Colors.grey[400] : const Color(0xFF8E8E93),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black,
|
||||
color: isDark ? Colors.white : Colors.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -784,13 +833,14 @@ class _EntirePageState extends State<EntirePage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTopContentSection() {
|
||||
Widget _buildTopContentSection(bool isDark) {
|
||||
return _buildSection('热门内容', Icons.star, [
|
||||
_buildTopContentItem(
|
||||
'今日热门',
|
||||
_statsData?['top_hits_day'],
|
||||
Icons.today,
|
||||
const Color(0xFFFF9500),
|
||||
isDark,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildTopContentItem(
|
||||
@@ -798,6 +848,7 @@ class _EntirePageState extends State<EntirePage>
|
||||
_statsData?['top_hits_month'],
|
||||
Icons.calendar_month,
|
||||
const Color(0xFF007AFF),
|
||||
isDark,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildTopContentItem(
|
||||
@@ -805,6 +856,7 @@ class _EntirePageState extends State<EntirePage>
|
||||
_statsData?['top_hits_total'],
|
||||
Icons.history,
|
||||
const Color(0xFF5856D6),
|
||||
isDark,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildTopContentItem(
|
||||
@@ -812,8 +864,9 @@ class _EntirePageState extends State<EntirePage>
|
||||
_statsData?['top_like'],
|
||||
Icons.thumb_up,
|
||||
const Color(0xFF34C759),
|
||||
isDark,
|
||||
),
|
||||
]);
|
||||
], isDark);
|
||||
}
|
||||
|
||||
Widget _buildTopContentItem(
|
||||
@@ -821,6 +874,7 @@ class _EntirePageState extends State<EntirePage>
|
||||
dynamic data,
|
||||
IconData icon,
|
||||
Color color,
|
||||
bool isDark,
|
||||
) {
|
||||
final hasData = data != null && data is Map<String, dynamic>;
|
||||
final content = hasData ? data['name']?.toString() ?? '暂无数据' : '暂无数据';
|
||||
@@ -828,11 +882,11 @@ class _EntirePageState extends State<EntirePage>
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.04),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -857,10 +911,10 @@ class _EntirePageState extends State<EntirePage>
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black,
|
||||
color: isDark ? Colors.white : Colors.black,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -869,8 +923,8 @@ class _EntirePageState extends State<EntirePage>
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: hasData
|
||||
? const Color(0xFF3C3C43)
|
||||
: const Color(0xFF8E8E93),
|
||||
? (isDark ? Colors.grey[400] : const Color(0xFF3C3C43))
|
||||
: (isDark ? Colors.grey[500] : const Color(0xFF8E8E93)),
|
||||
height: 1.5,
|
||||
),
|
||||
maxLines: 3,
|
||||
@@ -884,7 +938,7 @@ class _EntirePageState extends State<EntirePage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBuildTimeCard() {
|
||||
Widget _buildBuildTimeCard(bool isDark) {
|
||||
final buildTime = _statsData?['build_time']?.toString() ?? '未知';
|
||||
|
||||
int days = 0;
|
||||
@@ -900,11 +954,11 @@ class _EntirePageState extends State<EntirePage>
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.04),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -930,12 +984,12 @@ class _EntirePageState extends State<EntirePage>
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
'建站时间',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black,
|
||||
color: isDark ? Colors.white : Colors.black,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
@@ -943,9 +997,11 @@ class _EntirePageState extends State<EntirePage>
|
||||
children: [
|
||||
Text(
|
||||
buildTime,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: Color(0xFF3C3C43),
|
||||
color: isDark
|
||||
? Colors.grey[400]
|
||||
: const Color(0xFF3C3C43),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
@@ -977,14 +1033,19 @@ class _EntirePageState extends State<EntirePage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSection(String title, IconData icon, List<Widget> children) {
|
||||
Widget _buildSection(
|
||||
String title,
|
||||
IconData icon,
|
||||
List<Widget> children,
|
||||
bool isDark,
|
||||
) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
color: isDark ? const Color(0xFF2A2A2A) : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.04),
|
||||
color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.04),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
@@ -1001,10 +1062,10 @@ class _EntirePageState extends State<EntirePage>
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black,
|
||||
color: isDark ? Colors.white : Colors.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import '../../../constants/app_constants.dart';
|
||||
import '../../../services/wakelock_service.dart';
|
||||
import '../../../services/isweb/wakelock_service.dart';
|
||||
import '../guide/beginner_page.dart';
|
||||
import 'dart:io' as io;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user