193 lines
11 KiB
Dart
193 lines
11 KiB
Dart
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);
|
||
}
|