import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../../../constants/app_constants.dart'; /// 时间: 2026-03-26 /// 功能: 隐私政策与软件协议页面 /// 介绍: 展示应用的隐私政策和用户协议 /// 最新变化: 将协议内容抽取成公共组件,支持其他页面调用 /// 公共协议内容组件 - 隐私政策 class PrivacyPolicyContent extends StatelessWidget { const PrivacyPolicyContent({super.key}); @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionTitle('关于情景诗词与隐私的声明'), _buildUpdateDate('2026.3.26'), const SizedBox(height: 24), _buildParagraph( '情景诗词 是由 弥勒市朋普镇微风暴网络科技工作室 (以下简称"我们")为您提供的,用于在诗词里旅行,在文化中生长的应用。本隐私声明由我们为处理您的个人信息而制定。', ), const SizedBox(height: 16), _buildParagraph( '我们非常重视您的个人信息和隐私保护,将会按照法律要求和业界成熟的安全标准,为您的个人信息提供相应的安全保护措施。', ), const SizedBox(height: 24), _buildSectionTitle('1. 我们如何收集和使用您的个人信息'), const SizedBox(height: 16), _buildParagraph( '我们仅在有合法性基础的情形下才会使用您的个人信息。根据适用的法律,我们可能会基于您的同意、为履行/订立您与我们的合同所必需、履行法定义务所必需等合法性基础,使用您的个人信息。', ), const SizedBox(height: 16), _buildSubSectionTitle('1.1 基于履行法定义务或其他法律法规规定的情形'), const SizedBox(height: 12), _buildParagraph('为了实现应用功能,在获取您的同意后我们需要收集您的以下信息:'), const SizedBox(height: 12), _buildBulletPoint('本地笔记数据,用于保存您创建的诗词笔记'), _buildBulletPoint('点赞记录,用于展示您收藏的诗词'), _buildBulletPoint('历史记录,用于记录您浏览过的诗词'), const SizedBox(height: 24), _buildSectionTitle('2. 设备权限调用'), const SizedBox(height: 16), _buildPermissionItem('存储权限', '用于保存和读取您的笔记、收藏等本地数据'), _buildPermissionItem('网络权限', '用于获取诗词内容和更新应用信息'), _buildPermissionItem('震动权限', '用于在执行操作时提供反馈提示'), _buildPermissionItem('分享能力', '调用系统分享功能,分享您的笔记、收藏等本地数据'), const SizedBox(height: 24), _buildSectionTitle('3. 管理您的个人信息'), const SizedBox(height: 16), _buildParagraph( '如您对您的数据主体权利有进一步要求或存在任何疑问、意见或建议,可通过本声明中"如何联系我们"章节中所述方式与我们取得联系,并行使您的相关权利。', ), const SizedBox(height: 24), _buildSectionTitle('4. 信息存储地点及期限'), const SizedBox(height: 16), _buildParagraph('4.1 我们承诺,除法律法规另有规定外,我们对您的信息的保存期限应当为实现处理目的所必要的最短时间。'), const SizedBox(height: 12), _buildParagraph('4.2 上述信息将会传输并保存至中国境内的服务器。'), const SizedBox(height: 24), _buildSectionTitle('5. 如何联系我们'), const SizedBox(height: 16), _buildParagraph('您可通过以下方式联系我们,并行使您的相关权利,我们会尽快回复。'), const SizedBox(height: 12), _buildContactInfo('开发者', '弥勒市朋普镇微风暴网络科技工作室'), _buildContactInfo('地址', '云南 昆明 西山区'), _buildContactInfo('邮箱', '2821981550@qq.com'), const SizedBox(height: 16), _buildParagraph( '如果您对我们的回复不满意,特别是当个人信息处理行为损害了您的合法权益时,您还可以通过向有管辖权的人民法院提起诉讼、向行业自律协会或政府相关管理机构投诉等外部途径进行解决。您也可以向我们了解可能适用的相关投诉途径的信息。', ), const SizedBox(height: 24), _buildEffectiveDate('2026年3月26日'), _buildBottomIndicator(), _buildParagraph(''), ], ), ); } Widget _buildSectionTitle(String title) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ); } Widget _buildSubSectionTitle(String title) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Text( title, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ); } Widget _buildParagraph(String text) { return Text( text, style: TextStyle(fontSize: 14, color: Colors.grey[700], height: 1.6), ); } Widget _buildBulletPoint(String text) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 6, height: 6, margin: const EdgeInsets.only(top: 6, left: 8, right: 12), decoration: BoxDecoration( color: AppConstants.primaryColor, shape: BoxShape.circle, ), ), Expanded( child: Text( text, style: TextStyle( fontSize: 14, color: Colors.grey[700], height: 1.5, ), ), ), ], ), ); } Widget _buildPermissionItem(String title, String desc) { return Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey.withValues(alpha: 0.2)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold), ), const SizedBox(height: 4), Text(desc, style: TextStyle(fontSize: 13, color: Colors.grey[600])), ], ), ); } Widget _buildContactInfo(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ SizedBox( width: 80, child: Text( '$label:', style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), ), ), Expanded( child: Text( value, style: TextStyle(fontSize: 14, color: Colors.grey[700]), ), ), ], ), ); } Widget _buildUpdateDate(String date) { return Text( '更新日期:$date', style: TextStyle(fontSize: 12, color: Colors.grey[500]), ); } Widget _buildEffectiveDate(String date) { return Text( '生效日期:$date', style: TextStyle(fontSize: 12, color: Colors.grey[500]), ); } 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]), ], ), ); } } /// 公共协议内容组件 - 用户协议 class UserAgreementContent extends StatelessWidget { const UserAgreementContent({super.key}); @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionTitle('用户协议'), _buildEffectiveDate('2026-03-26'), const SizedBox(height: 24), _buildParagraph( '欢迎使用 情景诗词(以下简称"本App")。本用户协议由 弥勒市朋普镇微风暴网络科技工作室 制定。用户在下载、安装、注册、登录、使用本App服务前,应当仔细阅读并充分理解本协议内容。用户开始使用本App,即视为同意本协议全部条款。', ), const SizedBox(height: 24), _buildSectionTitle('一、协议适用范围'), const SizedBox(height: 16), _buildParagraph( '本协议适用于用户与开发者 弥勒市朋普镇微风暴网络科技工作室 之间,关于用户使用 情景诗词 产品及服务所建立的权利义务关系。', ), const SizedBox(height: 24), _buildSectionTitle('二、服务内容'), const SizedBox(height: 16), _buildParagraph( '情景诗词 主要提供诗词浏览、收藏、笔记记录、历史记录等功能。具体服务内容以应用内实际展示为准,开发者可根据产品运营情况进行功能优化、升级和调整。', ), const SizedBox(height: 24), _buildSectionTitle('三、账号与安全'), const SizedBox(height: 16), _buildParagraph( '您应当确保使用本App时遵守相关法律法规。本App目前不需要注册账号,您的本地数据存储在您的设备上,请妥善保管您的设备。', ), const SizedBox(height: 24), _buildSectionTitle('四、用户行为规范'), const SizedBox(height: 16), _buildParagraph( '用户在使用本App过程中,应当遵守中华人民共和国法律法规,不得利用本App从事违法违规行为,不得发布或传播侵犯他人合法权益的内容,不得实施影响本App安全和稳定运行的行为。', ), const SizedBox(height: 24), _buildSectionTitle('五、知识产权'), const SizedBox(height: 16), _buildParagraph( '用户知悉并认可,本App(含程序代码、界面设计、功能及其更新、扩展、修复版本)相关权利均归开发者或合法权利人所有。', ), const SizedBox(height: 12), _buildParagraph( '本条所称"知识产权"包括但不限于著作权、商标权、专利权、商业秘密及反不正当竞争法等法律法规项下的一切相关权利。', ), const SizedBox(height: 12), _buildParagraph( '除法律法规另有规定或开发者书面授权外,用户仅获得基于本协议的个人、非独占、不可转让、可撤销的使用许可;用户不得对本App实施复制、修改、改编、翻译、出租、出借、出售、传播、反向工程、反编译、反汇编,或以其他方式尝试获取源代码。', ), const SizedBox(height: 24), _buildSectionTitle('六、责任限制'), const SizedBox(height: 16), _buildParagraph( '在法律允许范围内,对于因网络异常、设备故障、不可抗力、第三方服务异常等原因导致的服务中断或数据损失,开发者将在能力范围内及时修复或补救,但不承担超出法定范围的责任。', ), const SizedBox(height: 24), _buildSectionTitle('七、协议更新'), const SizedBox(height: 16), _buildParagraph( '开发者有权根据业务变化、监管要求或法律法规变化更新本协议。更新后的协议将在应用内公示,用户继续使用本App即视为接受更新后的协议内容。', ), const SizedBox(height: 24), _buildSectionTitle('八、适用法律与争议解决'), const SizedBox(height: 16), _buildParagraph( '本协议适用中华人民共和国法律。因本协议引发的争议,双方应先友好协商;协商不成的,提交被告住所地有管辖权的人民法院处理。', ), const SizedBox(height: 24), _buildSectionTitle('九、联系方式'), const SizedBox(height: 16), _buildContactInfo('开发者', '弥勒市朋普镇微风暴网络科技工作室'), _buildContactInfo('应用名称', '情景诗词'), _buildContactInfo('联系邮箱', '2821981550@qq.com'), const SizedBox(height: 24), _buildBottomIndicator(), _buildParagraph(''), ], ), ); } Widget _buildSectionTitle(String title) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), ); } Widget _buildParagraph(String text) { return Text( text, style: TextStyle(fontSize: 14, color: Colors.grey[700], height: 1.6), ); } Widget _buildContactInfo(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ SizedBox( width: 80, child: Text( '$label:', style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), ), ), Expanded( child: Text( value, style: TextStyle(fontSize: 14, color: Colors.grey[700]), ), ), ], ), ); } Widget _buildEffectiveDate(String date) { return Text( '生效日期:$date', style: TextStyle(fontSize: 12, color: Colors.grey[500]), ); } 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]), ], ), ); } } /// 隐私政策页面(完整页面) class PrivacyPage extends StatefulWidget { const PrivacyPage({super.key}); @override State createState() => _PrivacyPageState(); } class _PrivacyPageState extends State with TickerProviderStateMixin { late TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); } @override void dispose() { _tabController.dispose(); super.dispose(); } @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, bottom: TabBar( controller: _tabController, labelColor: AppConstants.primaryColor, unselectedLabelColor: Colors.grey[600], indicatorColor: AppConstants.primaryColor, indicatorWeight: 2, tabs: const [ Tab(text: '隐私政策'), Tab(text: '用户协议'), ], ), leading: IconButton( icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), onPressed: () => Navigator.of(context).pop(), ), actions: [ IconButton( icon: Icon(Icons.link, color: AppConstants.primaryColor), onPressed: () => _showOnlineLinkDialog(), tooltip: '在线版本', ), ], ), body: TabBarView( controller: _tabController, children: const [PrivacyPolicyContent(), UserAgreementContent()], ), ); } void _showOnlineLinkDialog() { showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ Icon(Icons.public, color: AppConstants.primaryColor), const SizedBox(width: 8), const Text('在线版本'), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('您可以访问以下链接查看最新版本的协议:', style: TextStyle(fontSize: 14)), const SizedBox(height: 16), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey[300]!), ), child: SelectableText( 'https://poe.vogov.cn/privacy.html', style: TextStyle( fontSize: 13, color: AppConstants.primaryColor, decoration: TextDecoration.underline, ), ), ), const SizedBox(height: 12), Text( '💡 点击下方按钮复制链接,在浏览器中打开查看', style: TextStyle(fontSize: 12, color: Colors.grey[600]), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('关闭'), ), ElevatedButton.icon( onPressed: () { Clipboard.setData( const ClipboardData(text: 'https://poe.vogov.cn/privacy.html'), ); Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('链接已复制到剪贴板'), backgroundColor: AppConstants.primaryColor, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ); }, icon: const Icon(Icons.copy, size: 18), label: const Text('复制链接'), style: ElevatedButton.styleFrom( backgroundColor: AppConstants.primaryColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ), ], ), ); } }