import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../../constants/app_constants.dart'; /// 时间: 2026-03-26 /// 功能: 用户体验计划页面 /// 介绍: 展示用户体验计划的收集信息、权益说明,支持加入/退出 /// 最新变化: 新建页面 class UserPlanPage extends StatefulWidget { const UserPlanPage({super.key}); @override State createState() => _UserPlanPageState(); } class _UserPlanPageState extends State { bool _isJoined = false; bool _isLoading = true; @override void initState() { super.initState(); _loadUserPlanStatus(); } Future _loadUserPlanStatus() async { final prefs = await SharedPreferences.getInstance(); setState(() { _isJoined = prefs.getBool('user_plan_joined') ?? false; _isLoading = false; }); } Future _toggleUserPlan(bool value) async { final prefs = await SharedPreferences.getInstance(); await prefs.setBool('user_plan_joined', value); setState(() { _isJoined = value; }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(value ? '已加入用户体验计划' : '已退出用户体验计划'), backgroundColor: value ? AppConstants.primaryColor : Colors.grey[600], ), ); } } void _showJoinDialog() { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ Icon(Icons.volunteer_activism, color: AppConstants.primaryColor), const SizedBox(width: 8), const Text('加入用户体验计划'), ], ), content: const Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '加入后我们将收集以下信息以改善产品体验:', style: TextStyle(fontWeight: FontWeight.w500), ), SizedBox(height: 12), Text('• 软件使用时长'), Text('• 页面停留时间'), Text('• 个人喜爱诗词'), Text('• 分享次数'), Text('• 设备信息(IP归属地、设备型号)'), SizedBox(height: 12), Text( '所有数据将匿名化保存,不会公开。', style: TextStyle(color: Colors.grey, fontSize: 12), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), ElevatedButton( onPressed: () { Navigator.pop(context); _toggleUserPlan(true); }, style: ElevatedButton.styleFrom( backgroundColor: AppConstants.primaryColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text('同意并加入'), ), ], ), ); } void _showInfoPopup(BuildContext context) { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ Icon(Icons.info, color: AppConstants.primaryColor), const SizedBox(width: 8), const Text('温馨提示'), ], ), content: const Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '即使不加入用户体验计划,部分信息仍可能被收集:', style: TextStyle(fontWeight: FontWeight.w500), ), SizedBox(height: 12), Text('• 运营商可能收集网络连接信息'), Text('• 手机厂商可能收集软件使用数据'), Text('• 应用商店可能收集下载安装信息'), Text('• VPN、抓包等软件可能收集匿名统计数据'), SizedBox(height: 12), Text( '未加入用户体验计划,部分联网数据也会被动上传到软件服务器。', style: TextStyle(color: Colors.grey, fontSize: 12), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('我知道了'), ), ], ), ); } void _showExitDialog() { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: const Row( children: [ Icon(Icons.exit_to_app, color: Colors.red), SizedBox(width: 8), Text('退出用户体验计划'), ], ), content: const Text('退出后将不再收集您的使用数据,部分功能可能会受限。确定要退出吗?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), ElevatedButton( onPressed: () { Navigator.pop(context); _toggleUserPlan(false); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text('确定退出'), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5F5F5), appBar: AppBar( title: Text( '用户体验计划', style: TextStyle( color: AppConstants.primaryColor, fontWeight: FontWeight.bold, ), ), backgroundColor: Colors.white, elevation: 0, centerTitle: true, leading: IconButton( icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), onPressed: () => Navigator.of(context).pop(), ), ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : ListView( padding: const EdgeInsets.all(16), children: [ _buildStatusCard(), const SizedBox(height: 16), _buildCollectInfoSection(), const SizedBox(height: 16), _buildBenefitsSection(), const SizedBox(height: 16), _buildPrivacyNotice(), const SizedBox(height: 24), _buildActionButton(), const SizedBox(height: 16), _buildBottomIndicator(), ], ), ); } Widget _buildStatusCard() { return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( colors: [ AppConstants.primaryColor, AppConstants.primaryColor.withBlue(180), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: AppConstants.primaryColor.withValues(alpha: 0.3), blurRadius: 12, offset: const Offset(0, 4), ), ], ), child: Column( children: [ Icon( _isJoined ? Icons.verified : Icons.volunteer_activism_outlined, size: 48, color: Colors.white, ), const SizedBox(height: 12), Text( _isJoined ? '已加入用户体验计划' : '加入用户体验计划', style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), const SizedBox(height: 8), Text( _isJoined ? '感谢您的支持,让我们一起变得更好' : '参与产品改进,享受更多权益', style: TextStyle( fontSize: 14, color: Colors.white.withValues(alpha: 0.9), ), ), const SizedBox(height: 16), Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( _isJoined ? Icons.check_circle : Icons.info_outline, size: 16, color: Colors.white, ), const SizedBox(width: 6), Text( _isJoined ? '当前状态:已加入' : '当前状态:未加入', style: const TextStyle(fontSize: 13, color: Colors.white), ), ], ), ), ], ), ); } Widget _buildCollectInfoSection() { return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.orange.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.data_usage, color: Colors.orange[700], size: 20, ), ), const SizedBox(width: 12), const Text( '收集的信息', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ], ), ), const Divider(height: 1), _buildInfoItem(Icons.timer, '软件使用时长', '统计每日使用时长及时段'), _buildInfoItem(Icons.visibility, '不同页面停留时间', '了解用户关注的页面'), _buildInfoItem(Icons.favorite, '个人喜爱诗词', '推荐更精准的内容'), _buildInfoItem(Icons.error, '错误信息', '优化软件功能体验'), _buildInfoItem(Icons.location_on, 'IP归属地', '群体用户画像生成分析'), _buildInfoItem(Icons.devices, '设备信息', '适配更多设备型号'), Padding( padding: const EdgeInsets.all(16), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.blue.withValues(alpha: 0.05), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Icon(Icons.security, size: 16, color: Colors.blue[700]), const SizedBox(width: 8), Expanded( child: Text( '所有数据匿名化保存,不会公开,且定期删除', style: TextStyle(fontSize: 12, color: Colors.blue[700]), ), ), ], ), ), ), ], ), ); } Widget _buildInfoItem(IconData icon, String title, String subtitle) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ Icon(icon, size: 20, color: Colors.grey[600]), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 2), Text( subtitle, style: TextStyle(fontSize: 12, color: Colors.grey[500]), ), ], ), ), ], ), ); } Widget _buildBenefitsSection() { final benefits = [ {'icon': Icons.how_to_vote, 'title': '参与投票', 'desc': '对产品功能进行投票'}, {'icon': Icons.bar_chart, 'title': '查看统计数据', 'desc': '查看全站使用统计'}, {'icon': Icons.edit_note, 'title': '开放投稿', 'desc': '投稿您的诗词作品'}, {'icon': Icons.science, 'title': '体验Beta功能', 'desc': '内测版本抢先体验'}, {'icon': Icons.bug_report, 'title': '刷新次数', 'desc': '获得更多api调用次数'}, {'icon': Icons.card_giftcard, 'title': '专属显示', 'desc': '获得不同的显示效果'}, ]; return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.green.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.card_membership, color: Colors.green[700], size: 20, ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( '加入后的权益', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 2), Row( children: [ Text( '体验更多受限制的功能', style: TextStyle( fontSize: 11, color: Colors.grey[500], ), ), const SizedBox(width: 4), GestureDetector( onTap: () => _showInfoPopup(context), child: Icon( Icons.info_outline, size: 14, color: Colors.grey[500], ), ), ], ), ], ), ), ], ), ), const Divider(height: 1), Padding( padding: const EdgeInsets.all(12), child: GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 2.5, crossAxisSpacing: 8, mainAxisSpacing: 8, ), itemCount: benefits.length, itemBuilder: (context, index) { final benefit = benefits[index]; return Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.grey[50], borderRadius: BorderRadius.circular(8), border: Border.all( color: Colors.grey.withValues(alpha: 0.2), ), ), child: Row( children: [ Icon( benefit['icon'] as IconData, size: 18, color: AppConstants.primaryColor, ), const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( benefit['title'] as String, style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w500, ), ), Text( benefit['desc'] as String, style: TextStyle( fontSize: 10, color: Colors.grey[500], ), ), ], ), ), ], ), ); }, ), ), ], ), ); } Widget _buildPrivacyNotice() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.purple.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.privacy_tip, color: Colors.purple[700], size: 20, ), ), const SizedBox(width: 12), const Text( '隐私保护说明', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ], ), const SizedBox(height: 16), _buildPrivacyItem('🔒 数据匿名化处理,无法追溯到个人'), _buildPrivacyItem('🛡️ 数据仅用于产品改进,不会出售'), _buildPrivacyItem('📋 您可以随时退出计划'), _buildPrivacyItem('🗑️ 部分数据将被删除'), ], ), ); } Widget _buildPrivacyItem(String text) { return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ const SizedBox(width: 4), Expanded( child: Text( text, style: TextStyle( fontSize: 13, color: Colors.grey[700], height: 1.4, ), ), ), ], ), ); } Widget _buildActionButton() { return Container( width: double.infinity, height: 50, decoration: BoxDecoration( gradient: _isJoined ? null : LinearGradient( colors: [ AppConstants.primaryColor, AppConstants.primaryColor.withBlue(180), ], ), color: _isJoined ? Colors.grey[300] : null, borderRadius: BorderRadius.circular(12), boxShadow: _isJoined ? null : [ BoxShadow( color: AppConstants.primaryColor.withValues(alpha: 0.3), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: ElevatedButton( onPressed: () { if (_isJoined) { _showExitDialog(); } else { _showJoinDialog(); } }, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( _isJoined ? Icons.exit_to_app : Icons.volunteer_activism, color: _isJoined ? Colors.grey[600] : Colors.white, ), const SizedBox(width: 8), Text( _isJoined ? '退出用户体验计划' : '加入用户体验计划', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: _isJoined ? Colors.grey[600] : Colors.white, ), ), ], ), ), ); } Widget _buildBottomIndicator() { return Container( padding: const EdgeInsets.symmetric(vertical: 24), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container(width: 40, height: 1, color: Colors.grey[300]), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( '到底了', style: TextStyle(fontSize: 12, color: Colors.grey[400]), ), ), Container(width: 40, height: 1, color: Colors.grey[300]), ], ), ); } }