release 1.3.1

This commit is contained in:
Developer
2026-04-01 18:40:21 +08:00
parent 91ef47f991
commit f0a62ed68b
60 changed files with 1750 additions and 313 deletions

View File

@@ -1,5 +1,8 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:path_provider/path_provider.dart';
import '../../../constants/app_constants.dart';
/// 时间: 2026-03-27
@@ -17,6 +20,13 @@ class AppDataPage extends StatefulWidget {
class _AppDataPageState extends State<AppDataPage> {
int _sharedPrefsCount = 0;
bool _isLoading = true;
String _packageSize = '计算中...';
String _cacheSize = '计算中...';
String _dataSize = '计算中...';
String _totalSize = '计算中...';
int _packageBytes = 0;
int _cacheBytes = 0;
int _dataBytes = 0;
@override
void initState() {
@@ -27,12 +37,137 @@ class _AppDataPageState extends State<AppDataPage> {
Future<void> _loadDataInfo() async {
final prefs = await SharedPreferences.getInstance();
final keys = prefs.getKeys();
await Future.wait([
_calculatePackageSize(),
_calculateCacheSize(),
_calculateDataSize(),
]);
_calculateTotalSize();
setState(() {
_sharedPrefsCount = keys.length;
_isLoading = false;
});
}
Future<int> _getDirectorySize(Directory dir) async {
int totalSize = 0;
try {
if (await dir.exists()) {
await for (FileSystemEntity entity in dir.list(recursive: true)) {
if (entity is File) {
try {
totalSize += await entity.length();
} catch (e) {
debugPrint('获取文件大小失败: ${entity.path}, $e');
}
}
}
}
} catch (e) {
debugPrint('计算目录大小失败: ${dir.path}, $e');
}
return totalSize;
}
String _formatBytes(int bytes) {
if (bytes <= 0) return '0 B';
const suffixes = ['B', 'KB', 'MB', 'GB', 'TB'];
int i = (bytes.bitLength - 1) ~/ 10;
double size = bytes / (1 << (i * 10));
return '${size.toStringAsFixed(i == 0 ? 0 : 2)} ${suffixes[i]}';
}
Future<void> _calculatePackageSize() async {
try {
int totalSize = 0;
final tempDir = await getTemporaryDirectory();
final appDocDir = await getApplicationDocumentsDirectory();
final supportDir = await getApplicationSupportDirectory();
final parentDir = tempDir.parent;
if (await parentDir.exists()) {
await for (FileSystemEntity entity in parentDir.list()) {
if (entity is Directory) {
final dirName = entity.path.split(Platform.pathSeparator).last;
if (!dirName.startsWith('.')) {
totalSize += await _getDirectorySize(entity);
}
}
}
}
if (mounted) {
setState(() {
_packageBytes = totalSize;
_packageSize = _formatBytes(totalSize);
});
}
} catch (e) {
debugPrint('计算软件包大小失败: $e');
if (mounted) {
setState(() {
_packageSize = '获取失败';
});
}
}
}
Future<void> _calculateCacheSize() async {
try {
final tempDir = await getTemporaryDirectory();
final size = await _getDirectorySize(tempDir);
if (mounted) {
setState(() {
_cacheBytes = size;
_cacheSize = _formatBytes(size);
});
}
} catch (e) {
debugPrint('计算缓存大小失败: $e');
if (mounted) {
setState(() {
_cacheSize = '获取失败';
});
}
}
}
Future<void> _calculateDataSize() async {
try {
int totalSize = 0;
final appDocDir = await getApplicationDocumentsDirectory();
final supportDir = await getApplicationSupportDirectory();
totalSize += await _getDirectorySize(appDocDir);
totalSize += await _getDirectorySize(supportDir);
if (mounted) {
setState(() {
_dataBytes = totalSize;
_dataSize = _formatBytes(totalSize);
});
}
} catch (e) {
debugPrint('计算数据大小失败: $e');
if (mounted) {
setState(() {
_dataSize = '获取失败';
});
}
}
}
void _calculateTotalSize() {
const int appBaseSize = 10 * 1024 * 1024; // 10MB
final totalBytes = _packageBytes + _cacheBytes + _dataBytes + appBaseSize;
setState(() {
_totalSize = _formatBytes(totalBytes);
});
}
Future<void> _clearSharedPreferences() async {
final confirmed = await _showConfirmDialog(
'清空配置数据',
@@ -140,6 +275,55 @@ class _AppDataPageState extends State<AppDataPage> {
}
}
Future<void> _nativeClearData() async {
final confirmed = await _showConfirmDialog(
'系统层清理数据',
'⚠️ 危险操作 ⚠️\n\n确定要系统层清理数据吗?\n\n这将删除:\n• 应用文档目录所有文件\n• 应用支持目录所有文件\n• 应用缓存目录所有文件\n\n此操作将直接删除文件系统数据,不可撤销!',
);
if (confirmed != true) return;
final doubleConfirmed = await _showConfirmDialog(
'再次确认',
'这是系统层面文件系统删除!\n\n删除后数据将无法恢复,确定继续吗?',
);
if (doubleConfirmed != true) return;
try {
final tempDir = await getTemporaryDirectory();
final appDocDir = await getApplicationDocumentsDirectory();
final supportDir = await getApplicationSupportDirectory();
debugPrint('开始清理...');
debugPrint('临时目录: ${tempDir.path}');
debugPrint('文档目录: ${appDocDir.path}');
debugPrint('支持目录: ${supportDir.path}');
await _deleteDirectory(tempDir);
await _deleteDirectory(appDocDir);
await _deleteDirectory(supportDir);
debugPrint('原生清理完成');
if (mounted) {
Navigator.of(context).pop();
Future.delayed(const Duration(milliseconds: 300), () {
if (mounted) {
_showExitConfirmDialog();
}
});
}
} catch (e) {
debugPrint('原生清理失败: $e');
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('清理失败: $e'), backgroundColor: Colors.red),
);
}
}
}
Future<void> _clearCache() async {
final confirmed = await _showConfirmDialog(
'清空缓存',
@@ -148,13 +332,49 @@ class _AppDataPageState extends State<AppDataPage> {
if (confirmed != true) return;
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('缓存已清空'),
backgroundColor: AppConstants.primaryColor,
),
);
try {
final tempDir = await getTemporaryDirectory();
if (await tempDir.exists()) {
await _deleteDirectory(tempDir);
}
await _calculateCacheSize();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('缓存已清空'),
backgroundColor: AppConstants.primaryColor,
),
);
}
} catch (e) {
debugPrint('清空缓存失败: $e');
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('清空失败: $e'), backgroundColor: Colors.red),
);
}
}
}
Future<void> _deleteDirectory(Directory dir) async {
try {
if (await dir.exists()) {
await for (FileSystemEntity entity in dir.list()) {
if (entity is File) {
try {
await entity.delete();
} catch (e) {
debugPrint('删除文件失败: ${entity.path}, $e');
}
} else if (entity is Directory) {
await _deleteDirectory(entity);
}
}
}
} catch (e) {
debugPrint('删除目录失败: ${dir.path}, $e');
}
}
@@ -221,6 +441,46 @@ class _AppDataPageState extends State<AppDataPage> {
);
}
Future<void> _showExitConfirmDialog() async {
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
title: Row(
children: [
Icon(Icons.power_settings_new, color: Colors.deepOrange[700]),
const SizedBox(width: 8),
const Expanded(child: Text('关闭应用', style: TextStyle(fontSize: 18))),
],
),
content: const Text('数据清理完成!\n\n建议关闭应用后重新启动,\n以确保应用正常运行。\n\n是否现在关闭应用?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text('稍后关闭', style: TextStyle(color: Colors.grey[600])),
),
ElevatedButton(
onPressed: () => Navigator.pop(context, true),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepOrange[700],
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text('立即关闭'),
),
],
),
);
if (confirmed == true) {
if (mounted) {
SystemNavigator.pop();
}
}
}
void _showSnackBar(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
@@ -303,13 +563,15 @@ class _AppDataPageState extends State<AppDataPage> {
],
),
),
_buildDataItem('📦 软件包', '情景诗词 v1.2.19'),
_buildDataItem('📦 软件包', _packageSize),
_buildDivider(),
_buildDataItem('📱 配置项数量', '$_sharedPrefsCount'),
_buildDivider(),
_buildDataItem('💾 缓存大小', '计算中...'),
_buildDataItem('💾 缓存大小', _cacheSize),
_buildDivider(),
_buildDataItem('📊 数据大小', '计算中...'),
_buildDataItem('📊 数据大小', _dataSize),
_buildDivider(),
_buildDataItem('📁 占用空间', _totalSize),
],
),
);
@@ -506,6 +768,14 @@ class _AppDataPageState extends State<AppDataPage> {
Colors.red,
_clearAllData,
),
_buildDivider(),
_buildActionButton(
'🔧 原生清理数据',
'删除应用数据目录所有文件',
Icons.system_security_update_warning,
Colors.orange,
_nativeClearData,
),
],
),
);

View File

@@ -0,0 +1,860 @@
import 'package:flutter/material.dart';
import '../../../constants/app_constants.dart';
import 'sp-guide.dart';
class BeginnerPage extends StatefulWidget {
const BeginnerPage({super.key});
@override
State<BeginnerPage> createState() => _BeginnerPageState();
}
class _BeginnerPageState extends State<BeginnerPage>
with TickerProviderStateMixin {
final ScrollController _scrollController = ScrollController();
late AnimationController _fadeController;
late Animation<double> _fadeAnimation;
double _progress = 0.0;
final List<Map<String, dynamic>> _tutorialSections = [
{
'title': '首页功能',
'icon': Icons.home,
'emoji': '🏠',
'color': AppConstants.primaryColor,
'features': [
'精美卡片展示',
'智能推荐:根据时间和情景推荐合适的诗词',
'诗词详情:显示标题、作者、朝代、正文、注释和赏析',
'精选诗句:突出显示经典名句',
'下拉刷新:刷新诗词内容',
],
},
{
'title': '发现页面',
'icon': Icons.explore,
'emoji': '🔍',
'color': const Color(0xFF00BCD4),
'features': [
'分类浏览:按朝代、作者、主题等分类浏览',
'热门诗词:查看最受欢迎的诗词',
'活跃排行:查看活跃度最高的诗词',
'搜索功能:通过关键词搜索诗词',
'Tab切换分类、热门、搜索标签页',
],
},
{
'title': '足迹页面',
'icon': Icons.history,
'emoji': '📚',
'color': const Color(0xFFFF9800),
'features': [
'收藏管理:查看和管理所有收藏的诗词',
'笔记功能:创建和管理诗词笔记',
'分类展示:全部、点赞、笔记等分类',
'搜索功能:搜索收藏内容',
'视图切换:网格和列表视图',
],
},
{
'title': '个人中心',
'icon': Icons.person,
'emoji': '👤',
'color': const Color(0xFF4CAF50),
'features': [
'个人信息:编辑昵称、头像等',
'统计数据:今日浏览、累计浏览、今日点赞等',
'数据隐藏:可隐藏统计和答题数据',
'用户计划:加入用户体验计划',
'功能入口:设置、了解我们、权限管理等',
],
},
{
'title': '诗词阅读',
'icon': Icons.menu_book,
'emoji': '📖',
'color': const Color(0xFF9C27B0),
'features': [
'加载诗词:点击卡片任意区域加载下一条',
'查看详情:显示完整诗词信息',
'点赞诗词:点击心形图标',
'切换诗词:上一条/下一条按钮',
'长按复制:长按复制诗词内容',
],
},
{
'title': '收藏功能',
'icon': Icons.favorite,
'emoji': '❤️',
'color': const Color(0xFFE91E63),
'features': [
'一键收藏:点击收藏图标',
'收藏列表:在足迹页查看',
'取消收藏:再次点击收藏图标',
'收藏统计:显示收藏数量',
'创建笔记:从诗词创建笔记',
],
},
{
'title': '搜索功能',
'icon': Icons.search,
'emoji': '🔎',
'color': const Color(0xFF009688),
'features': [
'关键词搜索:输入关键词搜索',
'分类筛选:按分类筛选结果',
'热门搜索:查看热门搜索词',
'搜索历史:保留搜索记录',
'实时搜索:输入即时搜索',
],
},
{
'title': '答题挑战',
'icon': Icons.quiz,
'emoji': '🎮',
'color': const Color(0xFFFF5722),
'features': [
'答题挑战:参与诗词答题',
'题目随机化使用Fisher-Yates算法',
'答题记录:记录历史和成绩',
'答题统计:正确率等数据',
'提示功能:遇到困难可获取提示',
],
},
{
'title': '离线模式',
'icon': Icons.wifi_off,
'emoji': '📴',
'color': const Color(0xFF607D8B),
'features': [
'离线数据下载:支持下载诗词和答题',
'下载选项20/30/60/100条可选',
'后台下载:返回上一页继续下载',
'缓存管理:清空缓存可选择内容',
'自动切换:无网络自动切换',
],
},
{
'title': '个性化设置',
'icon': Icons.palette,
'emoji': '🎨',
'color': const Color(0xFF3F51B5),
'features': [
'主题切换:浅色/深色主题',
'卡片样式:三种样式可选',
'颜色自定义:主题色和背景色',
'圆角调整:卡片圆角大小',
'字体大小:调整字体大小',
],
},
{
'title': '投稿功能',
'icon': Icons.send,
'emoji': '📝',
'color': const Color(0xFF00BCD4),
'features': [
'诗词投稿:向软件投稿诗词',
'投稿表单:填写诗词信息',
'投稿记录:查看历史投稿',
'相似度检测:防止重复投稿',
'清空记录:清空投稿历史',
],
},
{
'title': '投票功能',
'icon': Icons.how_to_vote,
'emoji': '🗳️',
'color': const Color(0xFF795548),
'features': [
'用户投票:参与功能投票',
'投票结果:查看统计',
'登录注册:用户身份',
'自动注册:简化流程',
'投票详情:查看选项',
],
},
{
'title': '桌面卡片',
'icon': Icons.wb_sunny,
'emoji': '🌤️',
'color': const Color(0xFFFFC107),
'features': [
'天气显示:显示当前天气',
'城市显示:所在城市',
'十二时辰:中国传统计时',
'时间标签:子丑寅卯辰巳午未申酉戌亥',
'智能更新:自动更新时间',
],
},
{
'title': '图片分享',
'icon': Icons.share,
'emoji': '📸',
'color': const Color(0xFF03A9F4),
'features': [
'诗词分享:生成图片分享',
'软件分享:分享给朋友',
'复制功能:复制内容',
'高清图片:生成高质量图片',
'跨平台:支持多平台分享',
],
},
{
'title': '数据管理',
'icon': Icons.storage,
'emoji': '💾',
'color': const Color(0xFF8BC34A),
'features': [
'数据统计:显示数据占用',
'清空数据:清空应用数据',
'数据备份:备份数据',
'缓存管理:管理缓存',
'离线数据:管理离线数据',
],
},
{
'title': '帮助与反馈',
'icon': Icons.help,
'emoji': '',
'color': const Color(0xFF9E9E9E),
'features': [
'使用指南:查看使用说明',
'常见问题FAQ解答',
'用户反馈:反馈问题',
'功能建议:提交建议',
'已知Bug查看Bug列表',
],
},
];
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
_fadeController = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: this,
);
_fadeAnimation = CurvedAnimation(
parent: _fadeController,
curve: Curves.easeIn,
);
_fadeController.forward();
}
@override
void dispose() {
_scrollController.removeListener(_onScroll);
_scrollController.dispose();
_fadeController.dispose();
super.dispose();
}
void _onScroll() {
if (_scrollController.hasClients) {
final maxScroll = _scrollController.position.maxScrollExtent;
final currentScroll = _scrollController.position.pixels;
final progress = maxScroll > 0 ? currentScroll / maxScroll : 0.0;
if (mounted) {
setState(() {
_progress = progress;
});
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
body: Stack(
children: [
FadeTransition(
opacity: _fadeAnimation,
child: CustomScrollView(
controller: _scrollController,
slivers: [
SliverAppBar(
title: const Text(
'软件功能',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 17,
color: AppConstants.primaryColor,
),
),
backgroundColor: Colors.white,
foregroundColor: AppConstants.primaryColor,
elevation: 0,
centerTitle: true,
floating: true,
snap: true,
pinned: false,
actions: [
IconButton(
icon: const Icon(Icons.help_outline),
color: AppConstants.primaryColor,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const SpGuidePage(fromSettings: true),
),
);
},
),
],
),
SliverPadding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 100),
sliver: SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return _buildSectionCard(_tutorialSections[index], index);
}, childCount: _tutorialSections.length),
),
),
],
),
),
_buildProgressIndicator(),
],
),
);
}
Widget _buildSectionCard(Map<String, dynamic> section, int index) {
return TweenAnimationBuilder<double>(
tween: Tween(begin: 0.0, end: 1.0),
duration: Duration(milliseconds: 300 + (index * 50)),
curve: Curves.easeOut,
builder: (context, value, child) {
return Transform.translate(
offset: Offset(0, 20 * (1 - value)),
child: Opacity(opacity: value, child: child),
);
},
child: Container(
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.05),
blurRadius: 12,
offset: const Offset(0, 2),
),
],
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: (section['color'] as Color).withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(14),
),
child: Center(
child: Text(
section['emoji'],
style: const TextStyle(fontSize: 24),
),
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
section['title'],
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Colors.black87,
letterSpacing: -0.3,
),
),
const SizedBox(height: 4),
Text(
'${index + 1} 部分',
style: TextStyle(
fontSize: 13,
color: Colors.grey[500],
fontWeight: FontWeight.w400,
),
),
],
),
),
],
),
const SizedBox(height: 20),
_buildSectionContent(section['features'], section['color']),
const SizedBox(height: 16),
if (index < 4) ...[
const Divider(height: 1, color: Color(0xFFF5F5F5)),
const SizedBox(height: 16),
_buildPreviewSection(section['title']),
],
],
),
),
),
);
}
Widget _buildSectionContent(List<String> features, Color color) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: features.map((feature) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 6,
height: 6,
margin: const EdgeInsets.only(top: 8, right: 12),
decoration: BoxDecoration(color: color, shape: BoxShape.circle),
),
Expanded(
child: Text(
feature,
style: TextStyle(
fontSize: 15,
color: Colors.grey[700],
height: 1.5,
fontWeight: FontWeight.w400,
),
),
),
],
),
);
}).toList(),
);
}
Widget _buildPreviewSection(String title) {
Widget preview;
switch (title) {
case '首页功能':
preview = _buildHomePreview();
break;
case '发现页面':
preview = _buildDiscoverPreview();
break;
case '足迹页面':
preview = _buildFootprintPreview();
break;
case '个人中心':
preview = _buildProfilePreview();
break;
default:
preview = const SizedBox.shrink();
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.visibility_outlined,
size: 16,
color: AppConstants.primaryColor,
),
const SizedBox(width: 6),
Text(
'界面预览',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppConstants.primaryColor,
),
),
],
),
const SizedBox(height: 12),
preview,
],
);
}
Widget _buildHomePreview() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: AppConstants.primaryColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(
Icons.book,
size: 18,
color: AppConstants.primaryColor,
),
),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'静夜思',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.grey[800],
),
),
Text(
'唐·李白',
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
),
],
),
],
),
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Text(
'床前明月光,疑是地上霜。\n举头望明月,低头思故乡。',
style: TextStyle(
fontSize: 14,
color: Colors.grey[700],
height: 1.6,
),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildPreviewAction(Icons.favorite_border, '点赞'),
_buildPreviewAction(Icons.bookmark_border, '收藏'),
_buildPreviewAction(Icons.share_outlined, '分享'),
],
),
],
),
);
}
Widget _buildDiscoverPreview() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: [
Icon(Icons.search, size: 18, color: Colors.grey[400]),
const SizedBox(width: 8),
Text(
'搜索诗词...',
style: TextStyle(fontSize: 14, color: Colors.grey[400]),
),
],
),
),
const SizedBox(height: 12),
Row(
children: [
_buildPreviewTag('唐诗'),
const SizedBox(width: 8),
_buildPreviewTag('宋词'),
const SizedBox(width: 8),
_buildPreviewTag('元曲'),
],
),
const SizedBox(height: 12),
_buildPreviewListItem('将进酒', '李白'),
const SizedBox(height: 8),
_buildPreviewListItem('水调歌头', '苏轼'),
],
),
);
}
Widget _buildFootprintPreview() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildPreviewStat('128', '收藏'),
_buildPreviewStat('45', '笔记'),
_buildPreviewStat('89', '点赞'),
],
),
const SizedBox(height: 12),
_buildPreviewListItem('静夜思', '已收藏'),
const SizedBox(height: 8),
_buildPreviewListItem('春晓', '有笔记'),
],
),
);
}
Widget _buildProfilePreview() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
Row(
children: [
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: AppConstants.primaryColor.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(24),
),
child: const Center(
child: Text('👤', style: TextStyle(fontSize: 24)),
),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'诗词爱好者',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.grey[800],
),
),
Text(
'Lv.12 · 诗意生活',
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
),
],
),
],
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildPreviewStat('156', '浏览'),
_buildPreviewStat('89', '点赞'),
_buildPreviewStat('45', '答题'),
],
),
],
),
);
}
Widget _buildPreviewAction(IconData icon, String label) {
return Column(
children: [
Icon(icon, size: 20, color: Colors.grey[600]),
const SizedBox(height: 4),
Text(label, style: TextStyle(fontSize: 11, color: Colors.grey[600])),
],
);
}
Widget _buildPreviewTag(String text) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: AppConstants.primaryColor.withValues(alpha: 0.3),
),
),
child: Text(
text,
style: TextStyle(
fontSize: 12,
color: AppConstants.primaryColor,
fontWeight: FontWeight.w500,
),
),
);
}
Widget _buildPreviewListItem(String title, String subtitle) {
return Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: TextStyle(
fontSize: 14,
color: Colors.grey[700],
fontWeight: FontWeight.w500,
),
),
Text(
subtitle,
style: TextStyle(fontSize: 12, color: Colors.grey[500]),
),
],
),
);
}
Widget _buildPreviewStat(String value, String label) {
return Column(
children: [
Text(
value,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppConstants.primaryColor,
),
),
const SizedBox(height: 2),
Text(label, style: TextStyle(fontSize: 11, color: Colors.grey[500])),
],
);
}
Widget _buildProgressIndicator() {
return Positioned(
left: 0,
top: 0,
bottom: 0,
child: Container(
width: 60,
padding: const EdgeInsets.symmetric(vertical: 20),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Colors.white.withValues(alpha: 0.95),
Colors.white.withValues(alpha: 0.85),
Colors.white.withValues(alpha: 0.0),
],
stops: const [0.0, 0.7, 1.0],
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 8,
height: 200,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(4),
),
child: Stack(
children: [
AnimatedPositioned(
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut,
top: _progress * 160,
child: Container(
width: 8,
height: 40,
decoration: BoxDecoration(
color: AppConstants.primaryColor,
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: AppConstants.primaryColor.withValues(
alpha: 0.3,
),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
),
),
],
),
),
const SizedBox(height: 12),
AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: AppConstants.primaryColor,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: AppConstants.primaryColor.withValues(alpha: 0.2),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Text(
'${(_progress * 100).toInt()}%',
style: const TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w600,
letterSpacing: -0.2,
),
),
),
],
),
),
);
}
}

View File

@@ -475,7 +475,7 @@ class _SpGuidePageState extends State<SpGuidePage>
),
),
const SizedBox(width: 8),
_buildShowGuideCheckbox(),
// _buildShowGuideCheckbox(),
],
),
],