import 'package:flutter/material.dart'; import 'package:airhub_app/theme/design_tokens.dart'; import 'package:airhub_app/widgets/animated_gradient_background.dart'; class SettingsContentPage extends StatelessWidget { final String title; final String date; final List children; const SettingsContentPage({ super.key, required this.title, required this.date, required this.children, }); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.transparent, body: Stack( children: [ const AnimatedGradientBackground(), Column( children: [ _buildHeader(context), Expanded( child: ShaderMask( shaderCallback: (Rect rect) { return const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.transparent, Colors.black, Colors.black, Colors.transparent], stops: [0.0, 0.12, 0.92, 1.0], ).createShader(rect); }, blendMode: BlendMode.dstIn, child: SingleChildScrollView( padding: EdgeInsets.only( top: 20, left: 24, right: 24, bottom: 40 + MediaQuery.of(context).padding.bottom, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ...children, const SizedBox(height: 40), Center( child: Text( '更新日期:$date', style: const TextStyle( color: AppColors.textSecondary, fontSize: 13, ), ), ), ], ), ), ), ), ], ), ], ), ); } Widget _buildHeader(BuildContext context) { return Container( padding: EdgeInsets.only( top: MediaQuery.of(context).padding.top + 20, left: AppSpacing.lg, right: AppSpacing.lg, bottom: AppSpacing.md, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( onTap: () => Navigator.pop(context), child: Container( width: 40, height: 40, decoration: BoxDecoration( color: AppColors.iconBtnBg, borderRadius: BorderRadius.circular(AppRadius.button), ), child: const Icon( Icons.arrow_back_ios_new, color: AppColors.textPrimary, size: 18, ), ), ), Text(title, style: AppTextStyles.title), const SizedBox(width: 40), // Balance ], ), ); } } // Helper methods to generate text styles Widget buildSectionTitle(String text) { return Padding( padding: const EdgeInsets.only(top: 32, bottom: 12), child: Text( text, style: const TextStyle( fontSize: 17, fontWeight: FontWeight.w700, color: AppColors.textPrimary, ), ), ); } Widget buildParagraph(String text) { return Padding( padding: const EdgeInsets.only(bottom: 16), child: Text( text, textAlign: TextAlign.justify, style: const TextStyle( fontSize: 15, height: 1.6, color: Color(0xFF374151), ), ), ); } Widget buildBulletList(List items) { return Padding( padding: const EdgeInsets.only(bottom: 16, left: 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: items .map( (item) => Padding( padding: const EdgeInsets.only(bottom: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('• ', style: TextStyle(fontSize: 15, height: 1.6)), Expanded( child: Text( item, style: const TextStyle( fontSize: 15, height: 1.6, color: Color(0xFF374151), ), ), ), ], ), ), ) .toList(), ), ); } // Pre-defined pages content factories class AgreementPage extends StatelessWidget { const AgreementPage({super.key}); @override Widget build(BuildContext context) { return SettingsContentPage( title: '用户协议', date: '2025年1月15日', children: [ buildParagraph('欢迎您使用 Airhub 产品及服务!'), buildParagraph( '特别提示: 在您开始使用 Airhub 产品(以下简称"本产品")及相关服务之前,请您务必仔细阅读本《用户协议》(以下简称"本协议")。特别是涉及免除或者限制责任的条款、法律适用和争议解决条款等,请您重点阅读。', ), buildSectionTitle('1. 服务说明'), buildParagraph( '1.1 Airhub Team(以下简称"我们")向用户提供包括但不限于设备连接控制、AI 语音交互、角色记忆存储、云端同步等服务(以下简称"本服务")。', ), buildParagraph('1.2 本服务的具体内容由我们根据实际情况提供,我们有权随时变更、中断或终止部分或全部服务。'), buildParagraph('1.3 用户理解并同意,本服务仅供用户个人非商业性质的使用。用户不得利用本服务进行销售或其他商业用途。'), buildSectionTitle('2. 账号注册与使用'), buildParagraph('2.1 用户在使用本服务时需要注册一个 Airhub 账号。用户应保证注册信息的真实性、准确性和完整性。'), buildParagraph('2.2 用户有责任妥善保管注册账号信息及密码安全。因用户保管不善可能导致账号被盗及其后果,由用户自行承担。'), buildParagraph( '2.3 如发现任何未经授权使用您账号登录、使用本服务的情况,您应立即通知我们。您理解我们对您的任何请求采取行动需要合理时间,我们对在采取行动前已经产生的后果不承担责任。', ), buildSectionTitle('3. 用户行为规范'), buildParagraph('用户在使用本服务过程中,应当遵守法律法规,不得从事下列行为:'), buildBulletList([ '发布、传送、传播、储存危害国家安全、破坏社会稳定、违反公序良俗的内容;', '发布、传送、传播、储存侮辱、诽谤、淫秽、暴力、赌博等违法违规内容;', '利用 AI 功能生成虚假信息、诈骗信息或用于非法用途;', '对 AI 角色进行性骚扰、辱骂或诱导生成不当内容;', '进行任何危害计算机网络安全的行为,包括但不限于攻击、侵入他人系统。', ]), buildSectionTitle('4. 个人信息保护'), buildParagraph( '4.1 保护用户个人信息是我们的基本原则。我们将按照本协议及《隐私政策》的规定收集、使用、存储和分享您的个人信息。', ), // ... simplified for brevity, following the pattern ], ); } } class PrivacyPage extends StatelessWidget { const PrivacyPage({super.key}); @override Widget build(BuildContext context) { return SettingsContentPage( title: '隐私政策', date: '2025年1月15日', children: [ buildParagraph('Airhub (以下简称"我们")非常重视您的隐私。本隐私政策(以下简称"本政策")旨在向您说明我们在您使用 Airhub 产品及服务时如何收集、使用、保存、共享和转让您的个人信息,以及您所享有的相关权利。'), buildParagraph('请您在使用我们的服务前,仔细阅读并了解本政策。'), buildSectionTitle('1. 我们如何收集您的个人信息'), buildParagraph('为了向您提供优质的服务,我们会按照合法、正当、必要的原则收集您的信息:'), buildBulletList([ '账号注册信息:当您注册 Airhub 账号时,我们会收集您的手机号码或电子邮箱地址,用于验证身份及为您提供服务。', '设备连接信息:当您使用 Airhub 硬件设备时,我们会收集设备的 MAC 地址、SN 序列号、固件版本、IP 地址、Wi-Fi 信号强度等信息,以便实现设备连接、控制及固件升级功能。', '语音交互数据:当您使用语音功能与 AI 角色互动时,我们会收集您的语音指令及对话内容。这些数据将用于生成 AI 回复并优化模型效果。您可以选择不保留历史对话记录。', '角色记忆数据:您的 AI 角色养成数据(如亲密度、性格标签、记忆库)存储于云端,以便支持跨设备无缝迁移体验。', '日志信息:为保障服务安全及运行稳定,我们会收集您的操作日志、错误日志等。', ]), buildSectionTitle('2. 我们如何使用您的个人信息'), buildParagraph('我们将收集的信息用于以下用途:'), buildBulletList([ '提供各项服务:包括设备配网、远程控制、AI 语音对话等核心功能。', '产品优化:分析用户使用习惯,改善产品功能和用户体验。', '安全保障:监测账号异常状态,防范欺诈风险,保障系统安全。', '个性化推荐:基于您的角色记忆,为您提供更符合您偏好的 AI 个性化回复。', ]), buildSectionTitle('3. 信息的共享、转让与公开披露'), buildParagraph('3.1 共享:我们不会向任何第三方共享您的个人信息,但以下情况除外:'), buildBulletList([ '获得您的明确同意;', '为了实现核心功能需要与合作伙伴(如云服务提供商、语音识别技术提供商)共享必要信息;', '法律法规规定的情形。', ]), buildParagraph('3.2 转让:我们不会将您的个人信息转让给任何第三方,除非发生合并、收购或破产清算,我们将要求受让方继续受本政策约束。'), buildSectionTitle('4. 信息的存储与保护'), buildParagraph('4.1 存储地点:我们依照法律法规的规定,将收集的个人信息存储于中华人民共和国境内。'), buildParagraph('4.2 存储期限:我们仅在实现服务目的所必需的时间内保留您的个人信息。账号注销后,我们将对您的个人信息进行删除或匿名化处理。'), buildParagraph('4.3 安全措施:我们采用 SSL 加密传输、AES 数据加密存储、严格的访问权限控制等技术措施保护您的信息安全。'), buildSectionTitle('5. 您的权利'), buildParagraph('5.1 访问与更正:您有权登录 APP 查阅或修改您的个人信息。'), buildParagraph('5.2 删除:您可以通过【我的-设置-账号安全】申请注销账号。注销后,我们将删除您的所有数据且不可恢复。'), buildParagraph('5.3 撤回同意:您可以通过设备系统设置关闭相关权限(如麦克风权限),撤回您的授权。'), buildSectionTitle('6. 联系我们'), buildParagraph('如您对本隐私政策有任何疑问或投诉,请发送邮件至 privacy@airhub.com 联系我们。'), ], ); } } class CollectionListPage extends StatelessWidget { const CollectionListPage({super.key}); @override Widget build(BuildContext context) => SettingsContentPage( title: '个人信息收集清单', date: '2025年1月15日', children: [ buildParagraph('为了向您提供 Airhub 的核心服务,我们需要收集以下类型的个人信息。我们将严格遵守法律法规,保护您的个人信息安全。'), _buildInfoCard('基础功能服务', [ {'label': '收集信息类型', 'value': '手机号码、登录密码'}, {'label': '使用目的', 'value': '用于账号注册、登录、找回密码及身份认证'}, {'label': '收集场景', 'value': '用户注册或登录 APP 时'}, ]), _buildInfoCard('硬件连接与控制', [ {'label': '收集信息类型', 'value': 'Wi-Fi信息(SSID/BSSID)、蓝牙信息、设备序列号(SN)、MAC地址'}, {'label': '使用目的', 'value': '用于发现附近设备、建立蓝牙/Wi-Fi连接、设备配网及固件升级'}, {'label': '收集场景', 'value': '绑定设备、连接设备或使用设备控制功能时'}, ]), _buildInfoCard('AI 语音交互业务', [ {'label': '收集信息类型', 'value': '语音录音、对话文本、交互时间'}, {'label': '使用目的', 'value': '将语音转换为文本以理解指令、生成 AI 回复、优化语音识别模型'}, {'label': '收集场景', 'value': '使用语音对话功能与 AI 角色互动时'}, ]), _buildInfoCard('应用安全保障', [ {'label': '收集信息类型', 'value': '设备IMSI/IMEI、Android ID、IP地址、操作日志'}, {'label': '使用目的', 'value': '风控验证、安全防范、故障排查与分析'}, {'label': '收集场景', 'value': 'APP 运行期间(包括后台运行)'}, ]), ], ); static Widget _buildInfoCard(String title, List> rows) { return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.white.withOpacity(0.92), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFFECCFA8).withOpacity(0.2)), boxShadow: [ BoxShadow( color: const Color(0xFF8B5E3C).withOpacity(0.06), offset: const Offset(0, 4), blurRadius: 16, ), BoxShadow( color: Colors.black.withOpacity(0.02), offset: const Offset(0, 1), blurRadius: 4, ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(16), child: IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Left warm accent border strip Container( width: 4, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xFFECCFA8), Color(0xFFC99672)], ), ), ), // Card content Expanded( child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title with icon Row( children: [ Container( width: 28, height: 28, decoration: BoxDecoration( color: const Color(0xFFECCFA8).withOpacity(0.15), borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.shield_outlined, size: 16, color: Color(0xFFC99672), ), ), const SizedBox(width: 10), Text( title, style: const TextStyle( fontWeight: FontWeight.w700, color: Color(0xFF1F2937), fontSize: 16, ), ), ], ), const SizedBox(height: 16), // Info rows ...rows.asMap().entries.map((entry) { final isLast = entry.key == rows.length - 1; return Container( padding: EdgeInsets.only(bottom: isLast ? 0 : 10), margin: EdgeInsets.only(bottom: isLast ? 0 : 12), decoration: isLast ? null : BoxDecoration( border: Border( bottom: BorderSide( color: const Color(0xFFECCFA8).withOpacity(0.15), style: BorderStyle.solid, ), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( entry.value['label']!, style: const TextStyle( color: Color(0xFF9CA3AF), fontSize: 12, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 4), Text( entry.value['value']!, style: const TextStyle( color: Color(0xFF374151), fontWeight: FontWeight.w500, fontSize: 14, height: 1.4, ), ), ], ), ); }), ], ), ), ), ], ), ), ), ); } } class SharingListPage extends StatelessWidget { const SharingListPage({super.key}); @override Widget build(BuildContext context) => SettingsContentPage( title: '第三方信息共享清单', date: '2025年1月15日', children: [ buildParagraph('为保障 Airhub 的相关功能实现与应用安全稳定运行,我们可能会接入第三方提供的软件开发包(SDK)或服务。我们将审慎评估合作方的安全保障能力,并要求其遵守严格的保密协议。'), _buildShareCard( company: '阿里云计算有限公司', sdkType: '阿里云对象存储/API网关 SDK', purpose: '用于存储角色记忆数据、用户头像及语音文件,提供云端API服务稳定性。', data: '设备信息(IP地址)、网络连接状态。', method: 'SDK 本机采集', privacy: 'https://terms.aliyun.com/legal-agreement/terms', ), _buildShareCard( company: '深圳市腾讯计算机系统有限公司', sdkType: '微信开放平台 SDK', purpose: '用于支持微信账号一键登录、分享内容至微信朋友圈或会话。', data: '设备标识信息、微信个人授权信息(昵称、头像)。', method: 'SDK 本机采集', privacy: 'https://weixin.qq.com/cgi-bin/readtemplate?t=weixin_agreement', ), _buildShareCard( company: '深圳市和讯华谷信息技术有限公司', sdkType: '极光推送 (JPush) SDK', purpose: '用于实现消息推送功能,向您发送设备状态更新通知或系统公告。', data: '设备标识符(IMEI/MAC/Android ID/IDFA)、网络信息、应用安装列表。', method: 'SDK 本机采集', privacy: 'https://www.jiguang.cn/license/privacy', ), ], ); static Widget _buildShareCard({ required String company, required String sdkType, required String purpose, required String data, required String method, required String privacy, }) { return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.white.withOpacity(0.92), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFFECCFA8).withOpacity(0.2)), boxShadow: [ BoxShadow( color: const Color(0xFF8B5E3C).withOpacity(0.06), offset: const Offset(0, 4), blurRadius: 16, ), BoxShadow( color: Colors.black.withOpacity(0.02), offset: const Offset(0, 1), blurRadius: 4, ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(16), child: IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Left warm accent border strip Container( width: 4, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xFFECCFA8), Color(0xFFC99672)], ), ), ), // Card content Expanded( child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Container( padding: const EdgeInsets.only(bottom: 12), margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: const Color(0xFFECCFA8).withOpacity(0.15), ), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( company, style: const TextStyle( fontWeight: FontWeight.w700, fontSize: 16, color: Color(0xFF1F2937), ), ), const SizedBox(height: 6), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( gradient: LinearGradient( colors: [ const Color(0xFFECCFA8).withOpacity(0.15), const Color(0xFFC99672).withOpacity(0.1), ], ), borderRadius: BorderRadius.circular(6), ), child: Text( sdkType, style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: Color(0xFFB07D5A), ), ), ), ], ), ), // Rows _buildShareRow('使用目的', purpose), _buildShareRow('收集数据', data), _buildShareRow('共享方式', method), _buildShareRow('隐私政策', privacy), ], ), ), ), ], ), ), ), ); } static Widget _buildShareRow(String label, String value) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 70, child: Text( label, style: const TextStyle( color: Color(0xFF6B7280), fontSize: 13, ), ), ), Expanded( child: Text( value, style: const TextStyle( color: Color(0xFF374151), fontSize: 13, height: 1.5, ), ), ), ], ), ); } }