import 'package:flutter/material.dart'; import 'package:miaoji_zhang/shared/theme/app_theme.dart'; enum LegalDocumentKind { privacy('privacy', '隐私政策'), terms('terms', '用户协议'), permissions('permissions', '权限用途说明'), sdk('sdk', '第三方 SDK 清单'); final String key; final String title; const LegalDocumentKind(this.key, this.title); static LegalDocumentKind fromKey(String? key) => values.firstWhere((item) => item.key == key, orElse: () => privacy); } class LegalDocumentPage extends StatelessWidget { final LegalDocumentKind kind; const LegalDocumentPage({super.key, required this.kind}); static const _effectiveDate = '2026 年 7 月 25 日'; @override Widget build(BuildContext context) { final sections = _sections(kind); return Scaffold( appBar: AppBar(title: Text(kind.title)), body: SelectionArea( child: ListView( padding: const EdgeInsets.fromLTRB(18, 8, 18, 32), children: [ Text( '更新及生效日期:$_effectiveDate', style: TextStyle(fontSize: 12, color: context.jz.text3), ), SizedBox(height: 14), ...sections.map( (section) => Padding( padding: const EdgeInsets.only(bottom: 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( section.title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w800, color: context.jz.text, ), ), SizedBox(height: 8), Text( section.body, style: TextStyle( fontSize: 13.5, height: 1.75, color: context.jz.text2, ), ), ], ), ), ), ], ), ), ); } static List<_LegalSection> _sections(LegalDocumentKind kind) => switch (kind) { LegalDocumentKind.privacy => _privacy, LegalDocumentKind.terms => _terms, LegalDocumentKind.permissions => _permissions, LegalDocumentKind.sdk => _sdk, }; static const _privacy = <_LegalSection>[ _LegalSection( '一、我们如何处理信息', '记之由个人开发者丁伊文运营。我们重视你的个人信息与财务隐私。为提供账号、记账、统计、预算、AI 对话及数据导出功能,我们会处理你主动提交的账号名称、昵称、账本、分类、账单、预算、聊天文本,以及你主动选择的图片或截屏。密码仅以不可逆哈希形式保存在服务器,不保存明文密码。', ), _LegalSection( '二、语音、图片与 AI 数据', '使用语音记账时,麦克风音频由设备系统语音识别能力处理,记之接收识别后的文字;使用拍照或相册识别时,只有你主动选择的图片会用于本次识别。开启无障碍事件识别后,记之会在微信、支付宝疑似支付流程结束时按需截取当前页面,并由设备内置 OCR 在内存中识别。只有你另行开启 AI 批次对账时,支付结果页截图与本地候选才会按 30 秒空闲窗口成批发送至我们配置的火山方舟大模型服务,单批最长等待 2 分钟或累计 10 条。AI 仅可对当前批次执行保留、修正、补全或剔除,不能改动批次外账单。待提交图片只在设备上临时加密保存,批次完成或失败回退后立即删除。我们不会将完整账单历史无差别发送给模型,也不会把这些数据用于广告画像。', ), _LegalSection( '三、设备、网络与日志', '为保障登录和接口安全,服务器可能记录访问时间、网络地址、请求结果、应用版本及去标识化故障信息。故障日志不得记录密码、JWT、API Key、完整图片 Base64 或完整隐私内容。', ), _LegalSection( '四、存储期限与安全', '账号数据在你使用服务期间保存。你删除的账单进入 30 天回收站;AI 批次图片在批次完成或失败回退后立即删除,最近 7 天仅保留不含图片的批次操作摘要用于核对与恢复。手动截屏识别文件在完成、取消或失败后清理,遗留文件会在超过 24 小时后清理。账号注销进入 15 天后悔期,到期后永久删除账号关联数据。导出文件由你主动分享,应用会在分享完成或失败后清理临时副本。', ), _LegalSection( '五、你的权利', '你可以在应用内查询、更正和删除账单,导出数据,修改昵称或密码,撤回非必要权限,并申请注销账号。关闭麦克风、通知、相册选择、无障碍或截屏授权不会影响基础手工记账,但对应功能将无法使用。', ), _LegalSection( '六、未成年人、变更与联系', '未满 14 周岁的未成年人应在监护人同意和指导下使用。政策发生重要变化时,我们会通过应用内显著方式提示并重新征得必要同意。如对本政策、个人信息处理或账号注销有疑问,可发送邮件至 nanxun@nxsir.cn,或拨打 13607268374 联系运营者丁伊文。', ), ]; static const _terms = <_LegalSection>[ _LegalSection( '一、协议范围', '本协议是你与记之运营者丁伊文之间关于使用记之记账、统计、预算、AI 助手及相关服务的约定。注册或继续使用前,请完整阅读本协议与隐私政策。', ), _LegalSection( '二、账号使用', '你应提供真实、合法且不侵害他人权益的账号信息,妥善保管登录凭据,并对账号内操作负责。发现账号异常时应及时修改密码。修改密码会使其他设备的既有登录状态失效。', ), _LegalSection( '三、AI 功能说明', 'AI 识别和建议可能存在误差。涉及金额、收支类型、分类、时间和预算时,请在确认页面核对。AI 不构成投资、税务、法律或其他专业建议,最终记账和资金决策由你自行确认。', ), _LegalSection( '四、使用规范', '不得利用服务上传违法内容、攻击系统、窃取他人数据、绕过安全截屏限制或干扰服务运行。因系统维护、网络、上游模型或设备权限导致的暂时不可用,我们会尽力恢复并提供明确错误提示。', ), _LegalSection( '五、数据与注销', '你保留对自己输入数据的权利,并可通过应用导出。申请注销后账号进入 15 天后悔期,期间重新登录可取消;等待期结束后数据将按规则永久删除且无法恢复。', ), ]; static const _permissions = <_LegalSection>[ _LegalSection('麦克风', '仅在你主动长按语音输入或发起语音记账时使用,用于系统语音识别。拒绝后仍可使用键盘记账和文字聊天。'), _LegalSection( '相册与照片选择', '仅在你主动选择账单截图或图片识别时读取所选文件。Android 新版本优先使用系统照片选择器,不会扫描整套相册。', ), _LegalSection( '通知与振动', '用于展示 AI 图片识别进度、智能识别候选、自动入账结果以及撤销入口。拒绝后本地识别仍可运行,但后台结果和确认提示可能不可见。', ), _LegalSection( '无障碍服务', '可选权限。用于快捷磁贴静默截屏,以及在你主动开启“无障碍事件识别”后,仅处理微信、支付宝的支付流程事件、当前页面可见文字和按需本地截图 OCR。不会监听或拦截音量键,不会保存完整控件树;未开启 AI 批次对账时,本地 OCR 截图只在内存中处理。开启 AI 批次对账后,支付结果页会临时加密保存并按批上传,批次结束立即删除。关闭后基础手工记账仍可使用。', ), _LegalSection( '屏幕录制 / 截屏授权', '当无障碍截图不可用且你主动点击截屏记账时,系统会显示一次性授权。应用只截取一帧用于本次识别,完成后立即释放投屏会话;受保护页面不会尝试绕过系统限制。', ), _LegalSection('网络', '用于登录、同步账本、调用 AI 识别和获取配置。所有生产数据应通过受信任的 HTTPS 服务传输。'), ]; static const _sdk = <_LegalSection>[ _LegalSection( 'Flutter(Google)', '用于构建应用界面和跨平台运行。基础运行可能处理设备系统版本、界面状态及崩溃上下文;本项目未集成 Flutter 广告或行为分析 SDK。', ), _LegalSection( 'Dio(开源网络库)', '用于与记之后端进行 HTTPS 通信,传输登录凭据、账本数据、聊天文本和你主动提交的识别内容。', ), _LegalSection( 'flutter_secure_storage', '用于在设备安全存储中保存登录 Token。Android 使用系统加密存储能力,iOS 使用 Keychain。', ), _LegalSection( 'sqlite3 / SQLCipher', '用于在本机加密保存游客或账号的账本、分类、账单、预算及待同步操作。数据库密钥保存在系统安全存储中,本地数据库不会由该组件自行上传。', ), _LegalSection( 'archive', '用于在设备内存中生成 CSV 与 JSON 数据导出 ZIP,不连接网络、不收集数据;分享完成或失败后应用会清理临时 ZIP 文件。', ), _LegalSection('image_picker', '用于调用系统相册或照片选择器,只返回你主动选中的图片。'), _LegalSection('share_plus', '用于调用系统分享面板导出 ZIP。接收方由你选择;分享流程结束后应用清理临时导出文件。'), _LegalSection( 'ML Kit 中文文字识别(Google)', '用于在 Android 设备本地识别微信、支付宝支付结果页中的成功状态和金额。模型随应用安装,处理过程不需要登录或联网,不会由该 SDK 自行上传截图;图片仅在内存中使用并在完成后释放。', ), _LegalSection( '火山方舟大模型服务(字节跳动)', '用于 AI 对话、账单文本解析、图片识别、无障碍支付结果批次对账及预算草稿调整。会处理完成对应请求所需的文本、图片和最小化财务上下文,不接收密码、JWT 或 API Key。批次对账仅处理当前批次,图片在处理结束后由应用删除。', ), _LegalSection( 'Android / iOS 系统能力', '系统语音识别、照片选择器、通知、无障碍截图、MediaProjection 和系统分享属于操作系统能力,并非记之植入的广告或统计 SDK。', ), ]; } class _LegalSection { final String title; final String body; const _LegalSection(this.title, this.body); }